Trò chuyện với Gemini
Type 'KhachHangDAL' already defines a member called 'Update' with the same parameter types
Lỗi này xảy ra vì trong file KhachHangDAL.cs, bạn đang có hai hàm cùng tên là Update hoặc bạn đã copy đè đoạn code mới vào mà không xóa đoạn code cũ. Trong lập trình C#, một class không thể chứa hai thành phần có tên và tham số giống hệt nhau.
Để xử lý, bạn hãy mở file DAL/KhachHangDAL.cs và làm theo các bước sau:
1. Cách sửa lỗi trùng lặp (DAL)
Bạn hãy kiểm tra xem trong file có hai đoạn code nào cùng bắt đầu bằng public void Update(KhachHangBEL kh) không. Nếu có, hãy xóa bớt một cái và chỉ giữ lại một nội dung duy nhất như sau:
// --- Trong file DAL/KhachHangDAL.cs ---
public void Update(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
conn.Open();
string sql = "UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
cmd.ExecuteNonQuery();
}
}
2. Phân biệt nút "Lưu" và nút "Sửa" trên GUI
Dựa trên giao diện bạn đã thả, thường chúng ta sẽ xử lý như sau để chuyên nghiệp:
Nút Sửa: Dùng để thông báo cho hệ thống là người dùng muốn thay đổi dữ liệu (có thể làm TextBox sáng lên hoặc chỉ đơn giản là để người dùng biết).
Nút Lưu: Đây mới là nút thực hiện lệnh gọi xuống BAL để chạy SQL Update vào máy tính.
Code cho nút Lưu (btnLuu) trong frmKhachHang.cs:
private void btnLuu_Click(object sender, EventArgs e)
{
// Gom dữ liệu từ giao diện vào thùng BEL
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Gọi BAL để thực hiện cập nhật
string ketQua = bal.SuaKhachHang(kh);
MessageBox.Show(ketQua);
// Nạp lại bảng để thấy thay đổi
LoadData();
}
3. Code cho nút "Thoát"
Bạn nhấp đúp vào nút Thoát trên giao diện frmKhachHang và viết dòng này:
private void btnThoat_Click(object sender, EventArgs e)
{
DialogResult dr = MessageBox.Show("Bạn có chắc muốn thoát?", "Thông báo", MessageBoxButtons.YesNo);
if (dr == DialogResult.Yes)
{
this.Close(); // Đóng form khách hàng
}
}
Kiểm tra lại toàn bộ:
BEL: Có
KhachHangBELvới 4 thuộc tính (Ma, Ten, DC, DT).DAL: Có 1 hàm
Create, 1 hàmUpdate, 1 hàmDelete, 1 hàmReadKhachHang.BAL: Có các hàm tương ứng gọi xuống DAL.
GUI: Các nút bấm gọi đúng hàm ở BAL.
Bạn đã xóa được hàm trùng trong DAL chưa? Nếu rồi và không còn lỗi gạch đỏ, hãy thử chạy chương trình (F5), chọn 1 dòng khách hàng, sửa tên rồi nhấn Lưu xem dữ liệu có đổi không nhé. Bạn có muốn tôi hướng dẫn tiếp sang bảng PHÒNG không?
The name 'txtMaKH' does not exist in the current context
The name 'txtTenKH' does not exist in the current context
The name 'bal' does not exist in the current context
The name 'LoadData' does not exist in the current context
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
Các lỗi này xuất hiện vì 3 nguyên nhân chính: bạn chưa đặt tên đúng cho các ô nhập liệu, bạn chưa khai báo biến bal, hoặc bạn chưa viết hàm LoadData.
Hãy thực hiện sửa lỗi trực tiếp trong file GUI/frmKhachHang.cs theo 3 bước sau:
Bước 1: Đặt tên cho các Tool (Quan trọng nhất)
Lỗi 'txtMaKH' does not exist nghĩa là bạn kéo TextBox vào nhưng chưa đặt tên (Name) cho nó trong bảng thuộc tính.
Mở màn hình Design của
frmKhachHang.Chọn ô nhập Mã khách hàng -> Nhìn sang bảng Properties (góc dưới bên phải) -> Tìm dòng (Name) -> Gõ chính xác:
txtMaKH.Làm tương tự cho các ô khác:
txtTenKH,txtDiaChi,txtDienThoai.Chọn DataGridView -> Đặt tên (Name):
dgvKhachHang.
Bước 2: Khai báo biến bal và hàm LoadData
Bạn cần khai báo đối tượng xử lý ở đầu class để các nút bấm có thể sử dụng.
// --- Trong file GUI/frmKhachHang.cs ---
using QLKhachSan.BAL; // Phải có dòng này ở trên cùng
using QLKhachSan.BEL;
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
// 1. Khai báo biến bal ở đây để hết lỗi "bal does not exist"
KhachHangBAL bal = new KhachHangBAL();
public frmKhachHang()
{
InitializeComponent();
}
// 2. Viết hàm LoadData ở đây để hết lỗi "LoadData does not exist"
void LoadData()
{
// Lấy danh sách từ BAL và đổ vào DataGridView
dgvKhachHang.DataSource = bal.LayTatCa();
}
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData(); // Gọi hàm khi mở form
}
}
}
Bước 3: Kiểm tra lại các nút bấm
Sau khi đã đặt tên ở Bước 1, code trong các nút bấm sẽ tự động hết gạch đỏ.
Nút Lưu (Sửa):
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text, // Bây giờ máy đã hiểu txtMaKH là gì
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
MessageBox.Show(bal.SuaKhachHang(kh)); // Gọi BAL
LoadData();
}
Cách nhận biết bạn đã đặt tên đúng chưa:
Khi bạn gõ txt, nếu Visual Studio hiện ra gợi ý txtMaKH, txtTenKH trong danh sách xổ xuống thì nghĩa là bạn đã đặt tên thành công. Nếu không hiện, bạn phải quay lại màn hình Design để kiểm tra thuộc tính (Name).
Bạn đã đặt lại tên cho các TextBox chưa? Nếu làm xong 3 bước này, danh sách lỗi của bạn sẽ biến mất hoàn toàn. Bạn có muốn tôi hỗ trợ viết tiếp chức năng cho bảng PHÒNG không?
using QLKhachSan.BAL;
namespace QLKhachSan.GUI
{
partial class frmKhachHang
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
label1 = new Label();
label2 = new Label();
label3 = new Label();
label4 = new Label();
dataGridView1 = new DataGridView();
this.txtMaKH = new TextBox();
this.txtTenKH = new TextBox();
txtDiaChi = new TextBox();
txtDienThoai = new TextBox();
btnThem = new Button();
btnXoa = new Button();
btnSua = new Button();
btnLuu = new Button();
btnThoat = new Button();
((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit();
SuspendLayout();
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(34, 225);
label1.Name = "label1";
label1.Size = new Size(40, 15);
label1.TabIndex = 0;
label1.Text = "MaKH";
//
// label2
//
label2.AutoSize = true;
label2.Location = new Point(34, 268);
label2.Name = "label2";
label2.Size = new Size(41, 15);
label2.TabIndex = 1;
label2.Text = "TenKH";
//
// label3
//
label3.AutoSize = true;
label3.Location = new Point(34, 347);
label3.Name = "label3";
label3.Size = new Size(60, 15);
label3.TabIndex = 2;
label3.Text = "DienThoai";
//
// label4
//
label4.AutoSize = true;
label4.Location = new Point(34, 308);
label4.Name = "label4";
label4.Size = new Size(42, 15);
label4.TabIndex = 3;
label4.Text = "DiaChi";
//
// dataGridView1
//
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Location = new Point(34, 7);
dataGridView1.Name = "dataGridView1";
dataGridView1.Size = new Size(486, 197);
dataGridView1.TabIndex = 4;
//
// txtMaKH
//
this.txtMaKH.Location = new Point(96, 217);
this.txtMaKH.Name = "txtMaKH";
this.txtMaKH.Size = new Size(424, 23);
this.txtMaKH.TabIndex = 6;
//
// txtTenKH
//
this.txtTenKH.Location = new Point(96, 260);
this.txtTenKH.Name = "txtTenKH";
this.txtTenKH.Size = new Size(424, 23);
this.txtTenKH.TabIndex = 7;
//
// txtDiaChi
//
txtDiaChi.Location = new Point(96, 300);
txtDiaChi.Name = "txtDiaChi";
txtDiaChi.Size = new Size(424, 23);
txtDiaChi.TabIndex = 8;
//
// txtDienThoai
//
txtDienThoai.Location = new Point(96, 339);
txtDienThoai.Name = "txtDienThoai";
txtDienThoai.Size = new Size(424, 23);
txtDienThoai.TabIndex = 9;
//
// btnThem
//
btnThem.Location = new Point(34, 401);
btnThem.Name = "btnThem";
btnThem.Size = new Size(75, 23);
btnThem.TabIndex = 10;
btnThem.Text = "Thêm";
btnThem.UseVisualStyleBackColor = true;
//
// btnXoa
//
btnXoa.Location = new Point(129, 401);
btnXoa.Name = "btnXoa";
btnXoa.Size = new Size(75, 23);
btnXoa.TabIndex = 11;
btnXoa.Text = "Xoá";
btnXoa.UseVisualStyleBackColor = true;
//
// btnSua
//
btnSua.Location = new Point(224, 401);
btnSua.Name = "btnSua";
btnSua.Size = new Size(75, 23);
btnSua.TabIndex = 12;
btnSua.Text = "Sửa";
btnSua.UseVisualStyleBackColor = true;
//
// btnLuu
//
btnLuu.Location = new Point(318, 401);
btnLuu.Name = "btnLuu";
btnLuu.Size = new Size(75, 23);
btnLuu.TabIndex = 13;
btnLuu.Text = "Lưu";
btnLuu.UseVisualStyleBackColor = true;
btnLuu.Click += btnLuu_Click;
//
// btnThoat
//
btnThoat.Location = new Point(418, 401);
btnThoat.Name = "btnThoat";
btnThoat.Size = new Size(75, 23);
btnThoat.TabIndex = 14;
btnThoat.Text = "Thoát";
btnThoat.UseVisualStyleBackColor = true;
//
// frmKhachHang
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(btnThoat);
Controls.Add(btnLuu);
Controls.Add(btnSua);
Controls.Add(btnXoa);
Controls.Add(btnThem);
Controls.Add(txtDienThoai);
Controls.Add(txtDiaChi);
Controls.Add(this.txtTenKH);
Controls.Add(this.txtMaKH);
Controls.Add(dataGridView1);
Controls.Add(label4);
Controls.Add(label3);
Controls.Add(label2);
Controls.Add(label1);
Name = "frmKhachHang";
Text = "frmKhachHang";
((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label label1;
private Label label2;
private Label label3;
private Label label4;
private DataGridView dataGridView1;
private TextBox textBox1;
private TextBox textBox2;
private TextBox textBox3;
private TextBox txtDiaChi;
private TextBox txtDienThoai;
private Button btnThem;
private Button btnXoa;
private Button btnSua;
private Button btnLuu;
private Button btnThoat;
}
}
Đoạn code bạn vừa gửi là file frmKhachHang.Designer.cs (file tự động sinh ra khi bạn kéo thả). Trong file này, tôi thấy các biến như txtMaKH, txtTenKH đã xuất hiện nhưng lại đang bị khai báo chồng chéo hoặc thiếu ở file code chính.
Để giải quyết triệt để tất cả các lỗi "not exist", bạn hãy mở file frmKhachHang.cs (file code bạn viết bằng tay) và dán đè toàn bộ nội dung sau vào:
1. File: GUI/frmKhachHang.cs (Hoàn chỉnh)
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using QLKhachSan.BAL; // Gọi tầng BAL
using QLKhachSan.BEL; // Gọi tầng BEL
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
// Khai báo đối tượng BAL để sử dụng trong toàn Form
KhachHangBAL bal = new KhachHangBAL();
public frmKhachHang()
{
InitializeComponent();
}
// Hàm nạp dữ liệu từ Database lên GridView
void LoadData()
{
// dataGridView1 là tên mặc định trong file Designer của bạn
dataGridView1.DataSource = bal.LayTatCa();
}
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData();
}
// Sự kiện khi Click vào nút Lưu (Dùng để Sửa)
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
MessageBox.Show(bal.SuaKhachHang(kh)); // Gọi xử lý ở BAL
LoadData();
}
// Sự kiện khi Click vào nút Xoá
private void btnXoa_Click(object sender, EventArgs e)
{
string ma = txtMaKH.Text;
MessageBox.Show(bal.XoaKhachHang(ma)); // Gọi xử lý ở BAL
LoadData();
}
// Nút Thoát form
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
2. Sửa lỗi "txtMaKH does not exist" trong Designer
Trong file Designer bạn gửi, có một chỗ gây lỗi: bạn vừa dùng this.txtMaKH vừa khai báo private TextBox textBox1. Để đồng bộ, bạn hãy quay lại màn hình Design:
Chọn ô TextBox tương ứng với Mã khách hàng.
Trong bảng Properties, tìm dòng (Name), xóa chữ
textBox1và gõ lại chính xác:txtMaKH.Làm tương tự: đổi
textBox2thànhtxtTenKH.
3. Tại sao file của bạn lại báo lỗi?
Thiếu biến
bal: Bạn chưa khai báoKhachHangBAL bal = new KhachHangBAL();ở đầu class nên máy không biết gọi lệnh đi đâu.Thiếu hàm
LoadData: Máy báo lỗi vì bạn gọi lệnhLoadData()trong code nhưng chưa định nghĩa hàm đó làm nhiệm vụ gì.Sai tên Control: File Designer đang để tên là
dataGridView1nhưng trong code bạn có thể đang gọi làdgvKhachHang. Tôi đã chỉnh lại theo code Designer của bạn làdataGridView1.
Bạn hãy copy đoạn code ở mục 1 vào file frmKhachHang.cs nhé. Sau khi dán xong, nếu vẫn còn lỗi gạch đỏ nào, hãy cho tôi biết tên lỗi đó. Nếu đã chạy ổn, bạn có muốn tôi tiếp tục hướng dẫn làm chức năng cho bảng Phòng không?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
public frmKhachHang()
{
InitializeComponent();
}
private void btnLuu_Click(object sender, EventArgs e)
{
}
}
}
Để hoàn thiện file frmKhachHang.cs này mà không còn lỗi, bạn chỉ cần điền thêm phần khai báo tầng BAL và các hàm xử lý vào đúng vị trí.
Dưới đây là mã nguồn đầy đủ, bạn hãy chép đè vào file của mình:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using QLKhachSan.BAL; // Cần thiết để gọi tầng xử lý
using QLKhachSan.BEL; // Cần thiết để dùng thực thể KhachHangBEL
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
// 1. Khai báo lớp BAL để dùng chung cho cả Form
KhachHangBAL bal = new KhachHangBAL();
public frmKhachHang()
{
InitializeComponent();
}
// 2. Hàm nạp dữ liệu lên bảng (Viết riêng để dùng lại nhiều lần)
void LoadData()
{
// dataGridView1 là tên mặc định bạn đang có trong file Designer
dataGridView1.DataSource = bal.LayTatCa();
}
// 3. Sự kiện khi Form vừa mở lên
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData();
}
// 4. Code cho nút LƯU (Dùng để cập nhật dữ liệu)
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
string ketQua = bal.SuaKhachHang(kh); // Gọi tầng BAL xử lý
MessageBox.Show(ketQua);
LoadData(); // Cập nhật lại bảng hiển thị
}
// 5. Code cho nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
string ma = txtMaKH.Text;
MessageBox.Show(bal.XoaKhachHang(ma));
LoadData();
}
// 6. Code cho nút THÊM (Thêm mới khách hàng)
private void btnThem_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
MessageBox.Show(bal.ThemKhachHang(kh));
LoadData();
}
// 7. Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Lưu ý quan trọng để không bị lỗi:
Tên DataGridView: Trong file Designer của bạn, bảng đang tên là
dataGridView1. Nếu bạn đổi tên nó thànhdgvKhachHangthì trong code trên bạn cũng phải đổi lại tương ứng.Sự kiện Click: Bạn cần quay lại màn hình Design, chọn các nút Thêm, Xoá, Thoát và nhấp đúp chuột vào từng nút để Visual Studio tự tạo ra các "mối nối" (Event Handler) trong file Designer, nếu không code bạn viết ở đây sẽ không chạy khi bấm nút.
Hàm Load: Bạn chọn Form (bấm vào khoảng trống trên Form) -> Vào bảng Properties -> Chọn biểu tượng tia sét -> Nhấp đúp vào dòng Load để tạo sự kiện
frmKhachHang_Load.
Bạn đã dán code vào và chạy thử chưa? Nếu nút Lưu và Xoá đã hoạt động, bạn có muốn mình làm nốt bảng PHÒNG không? Bảng này sẽ làm y hệt các bước này nhưng thay "KhachHang" thành "Phong".
The name 'txtMaKH' does not exist in the current context
The name 'txtTenKH' does not exist in the current context
'KhachHangBAL' does not contain a definition for 'SuaKhachHang' and no accessible extension method 'SuaKhachHang' accepting a first argument of type 'KhachHangBAL' could be found (are you missing a using directive or an assembly reference?)
The name 'txtMaKH' does not exist in the current context
'KhachHangBAL' does not contain a definition for 'XoaKhachHang' and no accessible extension method 'XoaKhachHang' accepting a first argument of type 'KhachHangBAL' could be found (are you missing a using directive or an assembly reference?)
The name 'txtMaKH' does not exist in the current context
The name 'txtTenKH' does not exist in the current context
'KhachHangBAL' does not contain a definition for 'ThemKhachHang' and no accessible extension method 'ThemKhachHang' accepting a first argument of type 'KhachHangBAL' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtTenKH' and no accessible extension method 'txtTenKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
'frmKhachHang' does not contain a definition for 'txtMaKH' and no accessible extension method 'txtMaKH' accepting a first argument of type 'frmKhachHang' could be found (are you missing a using directive or an assembly reference?)
Lỗi này xuất hiện do tên các ô nhập liệu (TextBox) bạn đặt trong giao diện chưa khớp với tên trong code, và file KhachHangBAL của bạn vẫn đang để trống (không có hàm xử lý).
Để dứt điểm mống lỗi này, cậu hãy thực hiện đúng theo 2 bước sau:
Bước 1: Hoàn thiện file KhachHangBAL.cs (Folder BAL)
Cậu mở file KhachHangBAL.cs lên. Lỗi "does not contain a definition for..." là do file này hiện tại chưa có các hàm mà GUI đang gọi. Hãy dán đoạn code này vào:
using System;
using System.Collections.Generic;
using QLKhachSan.BEL; //
using QLKhachSan.DAL; //
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang(); //
public string ThemKhachHang(KhachHangBEL kh)
{
if (string.IsNullOrEmpty(kh.MaKH)) return "Mã không được trống!";
dal.Create(kh); //
return "Thêm thành công!";
}
public string SuaKhachHang(KhachHangBEL kh)
{
dal.Update(kh); //
return "Cập nhật thành công!";
}
public string XoaKhachHang(string ma)
{
dal.Delete(ma); //
return "Xóa thành công!";
}
}
}
Bước 2: Khắc phục lỗi "txtMaKH does not exist" trong frmKhachHang.cs
Lỗi này cực kỳ phổ biến khi làm WinForms. Có 2 nguyên nhân:
1. Kiểm tra lại thuộc tính (Name) trong Designer
Cậu mở màn hình thiết kế của frmKhachHang, click vào ô nhập Mã KH và Tên KH. Cậu kiểm tra trong bảng Properties:
Ô Mã KH phải đặt là:
txtMaKHÔ Tên KH phải đặt là:
txtTenKHLưu ý: Nếu cậu gõ là
txtMaKh(h viết thường) mà trong code gõtxtMaKH(H viết hoa) thì máy cũng báo lỗi không tìm thấy.
2. Đồng bộ file Code và file Designer
Cậu mở file frmKhachHang.cs và đảm bảo đoạn khai báo bal và các nút bấm được viết như sau:
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form //
{
// Phải có dòng này thì nút bấm mới hết lỗi "bal does not exist"
KhachHangBAL bal = new KhachHangBAL();
public frmKhachHang()
{
InitializeComponent();
}
void LoadData()
{
// dataGridView1 phải khớp tên với bên Designer
dataGridView1.DataSource = bal.LayTatCa();
}
// ... (các sự kiện nút bấm btnLuu_Click, btnXoa_Click viết ở đây)
}
}
Tóm tắt thứ tự xử lý:
Lưu file
KhachHangBAL.cstrước: Để hết lỗi gọi hàm.Vào Design đặt tên (Name) cho TextBox: Để hết lỗi
txtMaKH.Build (Ctrl + Shift + B): Để Visual Studio cập nhật lại danh sách tên control.
Cậu thử làm Bước 1 trước, sau đó Build lại xem danh sách lỗi có giảm đi đáng kể không? Nếu còn gạch đỏ ở đâu, cậu chụp màn hình chỗ đó mình chỉ tiếp cho! Cậu muốn mình hỗ trợ viết tiếp phần CellClick để click vào bảng thì chữ tự nhảy lên ô nhập không?
using System.Collections.Generic;
using QLKhachSan.BEL;
using QLKhachSan.DAL;
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang();
public void Them(KhachHangBEL kh) => dal.Create(kh);
public void Sua(KhachHangBEL kh) => dal.Update(kh);
public void Xoa(string ma) => dal.Delete(ma);
}
}
Vấn đề nằm ở đây rồi cậu ơi! Trong file BAL cậu vừa gửi, tên các hàm đang là Them, Sua, Xoa. Tuy nhiên, trong file GUI (giao diện) cậu lại đang gọi các tên khác như ThemKhachHang, SuaKhachHang, XoaKhachHang. Đó là lý do tại sao máy báo lỗi "does not contain a definition".
Để sửa lỗi này nhanh nhất, cậu hãy chọn một trong hai cách sau:
Cách 1: Sửa lại file KhachHangBAL.cs (Khuyên dùng)
Cậu đổi tên các hàm trong file BAL cho khớp với những gì cậu đã viết ở GUI. Hãy chép đè đoạn này vào file KhachHangBAL.cs của cậu:
using System.Collections.Generic;
using QLKhachSan.BEL;
using QLKhachSan.DAL;
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang();
// Đổi tên từ Them thành ThemKhachHang
public void ThemKhachHang(KhachHangBEL kh) => dal.Create(kh);
// Đổi tên từ Sua thành SuaKhachHang
public void SuaKhachHang(KhachHangBEL kh) => dal.Update(kh);
// Đổi tên từ Xoa thành XoaKhachHang
public void XoaKhachHang(string ma) => dal.Delete(ma);
}
}
Cách 2: Giải quyết lỗi txtMaKH và txtTenKH trong GUI
Sau khi sửa xong BAL, lỗi "does not exist" ở GUI vẫn còn nếu tên Control chưa khớp. Cậu cần làm chính xác như sau:
Vào lại màn hình Design của
frmKhachHang.Click chuột phải vào ô TextBox nhập Mã khách hàng -> Chọn Properties.
Tìm dòng (Name): Nếu nó đang là
textBox1hay gì đó, hãy xóa đi và gõ lại đúng:txtMaKH.Làm tương tự cho ô Tên khách hàng: Đặt lại tên là
txtTenKH.Quan trọng: Cậu nhìn lại file
frmKhachHang.Designer.cscậu gửi lúc nãy, chỗdataGridView1. Nếu trong code cậu gọi làdgvKhachHangthì cũng sẽ lỗi. Hãy đổi tên DataGridView trong Properties thànhdgvKhachHangluôn cho đồng bộ.
Bước cuối cùng: Nạp lại dữ liệu (CellClick)
Sau khi hết lỗi, để phần mềm dùng được "mượt", cậu nên thêm sự kiện này vào file frmKhachHang.cs (vùng code). Nó giúp khi cậu click vào 1 dòng trên bảng, dữ liệu tự hiện lên các ô TextBox để cậu Xóa hoặc Sửa:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
Cậu thử sửa lại tên hàm trong BAL theo Cách 1 xem danh sách lỗi có biến mất không? Nếu vẫn còn lỗi nào, cứ copy quăng lên đây tớ "diệt" nốt cho! Cậu đã làm xong bảng PHÒNG chưa hay để tớ lên danh sách các file cần tạo cho bảng đó?
them sua xoa luu thoat à
Để hoàn thiện các nút Thêm, Xóa, Sửa, Lưu, Thoát cho bảng Khách hàng mà không còn lỗi, cậu cần làm cho các "mối nối" giữa các tầng khớp nhau hoàn toàn về tên gọi.
Dưới đây là mã nguồn chuẩn, cậu hãy copy vào từng file tương ứng nhé:
1. Cập nhật File: BAL/KhachHangBAL.cs
Cậu hãy sửa lại file BAL cậu vừa gửi thành nội dung này để khớp tên hàm với tầng giao diện:
using System.Collections.Generic;
using QLKhachSan.BEL; //
using QLKhachSan.DAL; //
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang(); //
// Đổi tên để GUI gọi không bị lỗi
public void ThemKhachHang(KhachHangBEL kh) => dal.Create(kh); //
public void SuaKhachHang(KhachHangBEL kh) => dal.Update(kh); //
public void XoaKhachHang(string ma) => dal.Delete(ma); //
}
}
2. Cập nhật File: GUI/frmKhachHang.cs
Đây là nơi cậu xử lý các nút bấm. Hãy đảm bảo các tên txtMaKH, txtTenKH... đã được đặt đúng trong phần Properties > Name của Designer nhé.
using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dataGridView1.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
// Nút LƯU: Lấy dữ liệu từ TextBox và đẩy xuống BAL để lưu/sửa
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
3. Giải quyết nốt lỗi "txtMaKH does not exist"
Nếu dán code trên vào vẫn bị gạch đỏ ở txtMaKH:
Mở màn hình Design của
frmKhachHang.Click vào ô nhập Mã khách hàng.
Nhìn sang bảng Properties, tìm dòng (Name).
Xóa chữ
textBox1(hoặc tên cũ) và gõ đúng:txtMaKH.Làm tương tự cho các ô khác (
txtTenKH,txtDiaChi,txtDienThoai).
Mẹo để nút "Sửa" chạy mượt
Để khi click vào bảng dữ liệu tự nhảy lên các ô TextBox, cậu hãy nhấp đúp vào sự kiện CellClick của dataGridView1 và thêm:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
Cậu thử cập nhật lại file BAL và đặt lại Name cho các TextBox xem sao nhé. Nếu chạy được rồi, tớ sẽ hướng dẫn cậu làm nốt bảng PHÒNG cực nhanh dựa trên khuôn mẫu này! Cậu đã làm xong file PhongDAL.cs chưa?
nó lỗi có cho hiện design đâu mà vào pro
Tôi hiểu rồi, đây là tình trạng "tiến thoái lưỡng nan" đặc trưng của WinForms: Code lỗi làm hỏng Design, mà không vào được Design thì không sửa được thuộc tính để hết lỗi code.
Để thoát khỏi vòng lặp này, cậu hãy thực hiện sửa trực tiếp trong file Designer.cs theo các bước sau:
Bước 1: Sửa tên biến "bằng tay" trong file Designer
Cậu mở Solution Explorer, nhấp vào mũi tên nhỏ bên cạnh frmKhachHang.cs để thấy file frmKhachHang.Designer.cs. Mở nó lên và làm như sau:
Tìm đoạn khai báo biến ở cuối file (thường nằm dưới cùng).
Nếu thấy
private System.Windows.Forms.TextBox textBox1;, hãy đổi tên nó thành:private System.Windows.Forms.TextBox txtMaKH;Tương tự, đổi
textBox2thànhtxtTenKH.Kéo lên trên, tìm trong hàm
InitializeComponent(), chỗ nào cóthis.textBox1thì đổi hết thànhthis.txtMaKH.
Bước 2: Tạm thời "vô hiệu hóa" các dòng code lỗi ở file chính
Để màn hình Design hiện ra được, file code của cậu phải sạch lỗi biên dịch.
Mở file
frmKhachHang.cs.Bôi đen toàn bộ nội dung bên trong các hàm
btnLuu_Click,btnXoa_Click, v.v.Nhấn Ctrl + K + C để comment (biến chúng thành ghi chú màu xanh).
Lúc này file code sẽ không còn gạch đỏ nữa. Cậu nhấn Ctrl + Shift + B để Build lại dự án.
Bước 3: Mở lại Design và đặt tên chuẩn
Bây giờ cậu nhấp đúp vào frmKhachHang.cs, màn hình Design chắc chắn sẽ hiện ra.
Bây giờ cậu vào bảng Properties và đặt lại tên (Name) cho các TextBox như tớ hướng dẫn lúc nãy (
txtMaKH,txtTenKH,txtDiaChi,txtDienThoai).Đặt tên cho DataGridView là
dataGridView1(để khớp với code cũ).Quay lại file code chính, bỏ dấu comment (nhấn Ctrl + K + U) cho các đoạn code lúc nãy.
Bước 4: Đồng bộ hóa file BAL (Rất quan trọng)
Để không bị lỗi "does not contain a definition", cậu hãy copy chính xác đoạn này vào file BAL/KhachHangBAL.cs:
using System.Collections.Generic;
using QLKhachSan.BEL; //
using QLKhachSan.DAL; //
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang(); //
// Tên hàm phải giống hệt như GUI đang gọi
public void ThemKhachHang(KhachHangBEL kh) => dal.Create(kh); //
public void SuaKhachHang(KhachHangBEL kh) => dal.Update(kh); //
public void XoaKhachHang(string ma) => dal.Delete(ma); //
}
}
Mẹo nhỏ: Nếu cậu thấy quá rối, cậu có thể xóa các dòng code trong nút bấm ở file frmKhachHang.cs đi, mở Design lên, rồi nhấp đúp lại vào từng nút để Visual Studio tự tạo lại sự kiện cho chuẩn.
Cậu thử mở file Designer.cs sửa tên biến xem màn hình Design đã hiện lên chưa? Nếu hiện rồi thì báo tớ để mình đi tiếp nhé! Cậu có cần tớ hướng dẫn cách làm cho bảng PHÒNG mà không bị lỗi tương tự không?
này hả private Label label1;
private Label label2;
private Label label3;
private Label label4;
private DataGridView dataGridView1;
private TextBox textBox1;
private TextBox textBox2;
private TextBox textBox3;
private TextBox txtDiaChi;
private TextBox txtDienThoai;
private Button btnThem;
private Button btnXoa;
private Button btnSua;
private Button btnLuu;
private Button btnThoat;
Chính xác là đoạn đó rồi cậu! Đây là nơi Windows Form quản lý tên của các linh kiện trên giao diện.
Để hết lỗi và mở lại được màn hình Design, cậu hãy sửa lại các dòng textBox đó cho khớp với tên mà cậu đã viết trong code xử lý. Cậu hãy sửa đoạn đó thành thế này:
// Tìm và sửa lại các dòng này trong file frmKhachHang.Designer.cs
private Label label1;
private Label label2;
private Label label3;
private Label label4;
private DataGridView dataGridView1;
private TextBox txtMaKH; // Sửa từ textBox1 thành txtMaKH
private TextBox txtTenKH; // Sửa từ textBox2 thành txtTenKH
private TextBox txtDiaChi; // Đảm bảo tên này khớp với file .cs
private TextBox txtDienThoai; // Đảm bảo tên này khớp với file .cs
private Button btnThem;
private Button btnXoa;
private Button btnSua;
private Button btnLuu;
private Button btnThoat;
Các bước tiếp theo để "cứu" cái Form:
Sửa ở đầu file Designer: Cậu kéo lên trên cùng của file
frmKhachHang.Designer.cs, tìm trong hàmInitializeComponent(). Chỗ nào thấythis.textBox1thì đổi hết thànhthis.txtMaKH, tương tự vớithis.textBox2đổi thànhthis.txtTenKH.Lưu file Designer: Nhấn Ctrl + S để lưu lại.
Build dự án: Nhấn Ctrl + Shift + B. Nếu file
KhachHangBAL.cscủa cậu đã có đủ các hàmThemKhachHang,SuaKhachHang,XoaKhachHangthì mọi dấu gạch đỏ sẽ biến mất.Mở Design: Bây giờ cậu nhấp đúp vào file
frmKhachHang.cslà giao diện sẽ hiện ra bình thường.
Tại sao cậu nên làm vậy?
Khi cậu sửa trực tiếp trong Designer như thế này, cậu đang ép Visual Studio phải nhận diện tên biến mới mà không cần thông qua giao diện đồ họa (vốn đang bị lỗi không mở được).
Cậu sửa xong chưa? Nếu giao diện hiện lên rồi, hãy thử chạy chương trình và bấm nút Thêm thử xem. Nếu cậu muốn, tớ có thể hướng dẫn cậu làm tiếp bảng PHÒNG nhưng lần này tớ sẽ chỉ cậu mẹo để không bao giờ bị lỗi tên biến này nữa! Cậu có muốn thử không?
cứu được rồi giò tiếp theo vói datagridview đây
Chúc mừng cậu đã "cứu" được cái Form thành công! Bây giờ chúng ta sẽ xử lý phần quan trọng nhất để giao diện trông chuyên nghiệp: Đổ dữ liệu lên DataGridView và xử lý sự kiện khi click vào bảng.
Thực hiện theo các bước sau để đảm bảo không lỗi:
1. Nạp dữ liệu lên bảng (Load Data)
Mở file frmKhachHang.cs, hãy chắc chắn cậu có hàm này để khi mở Form lên là thấy ngay danh sách khách hàng:
// Hàm này gọi tầng BAL để lấy dữ liệu
void LoadData()
{
// dataGridView1 là tên biến trong file Designer của cậu
dataGridView1.DataSource = bal.LayTatCa();
}
// Gọi LoadData khi Form vừa mở
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData();
}
2. Sự kiện Click vào bảng hiện chữ lên TextBox
Đây là kỹ thuật giúp người dùng không phải gõ lại Mã KH khi muốn Xóa hoặc Sửa.
Vào màn hình Design, chọn
dataGridView1.Mở bảng Properties -> chọn biểu tượng tia sét (Events).
Tìm dòng CellClick, nhấp đúp chuột vào ô bên cạnh để nó tự sinh ra hàm.
Dán đoạn code này vào:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra nếu người dùng click vào dòng hợp lệ (không phải tiêu đề)
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
// Gán giá trị từ các cột (0, 1, 2, 3) vào các TextBox tương ứng
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
3. Làm đẹp DataGridView
Để bảng hiển thị đẹp và đầy đủ thông tin, cậu có thể chỉnh thêm vài thuộc tính trong cửa sổ Properties của dataGridView1:
AutoSizeColumnsMode: Chọn
Fill(Để các cột tự giãn đều màn hình).SelectionMode: Chọn
FullRowSelect(Để khi click là chọn cả dòng cho đẹp).ReadOnly: Chọn
True(Nếu cậu không muốn người dùng sửa trực tiếp trên bảng).
Bước tiếp theo: Làm bảng PHÒNG (Cực nhanh)
Bảng khách hàng coi như đã xong 99%. Bây giờ chúng ta sẽ áp dụng đúng công thức này cho bảng PHÒNG.
Thứ tự file cậu cần tạo (Không được sai):
PhongBEL.cs (Tạo cái thùng chứa: MaPhong, TenPhong, LoaiPhong...)
PhongDAL.cs (Viết SQL: Read, Create, Update, Delete)
PhongBAL.cs (Viết hàm gọi DAL: LayTatCa, ThemPhong, SuaPhong...)
frmPhong.cs (Giao diện y hệt bảng Khách hàng)
Cậu đã tạo đủ 3 file đầu (BEL, DAL, BAL) cho bảng PHÒNG chưa? Nếu rồi, hãy quăng code file PhongDAL.cs lên đây tớ kiểm tra xem có khớp tên hàm không để khi làm GUI không bị lỗi "not exist" nữa!
cưu
Chúc mừng cậu đã "hồi sinh" được cái Form! Khi giao diện đã hiện lên, việc xử lý DataGridView sẽ là bước cuối cùng để hoàn thiện chức năng xem và chọn dữ liệu.
Cậu hãy làm theo trình tự "chuẩn" sau đây để bảng hoạt động mượt mà:
1. Nạp dữ liệu vào DataGridView (Load Data)
Mọi dữ liệu muốn hiện lên bảng đều phải đi qua tầng BAL. Cậu mở file frmKhachHang.cs và thêm hàm này vào:
// Hàm đổ dữ liệu từ Database lên bảng
void LoadData()
{
// dataGridView1 là tên biến trong file Designer mà cậu vừa cứu
// bal.LayTatCa() sẽ gọi xuống DAL để lấy List khách hàng
dataGridView1.DataSource = bal.LayTatCa();
}
// Sự kiện chạy ngay khi Form mở lên
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData();
}
2. Xử lý sự kiện Click chọn dòng (CellClick)
Để khi cậu click chuột vào một dòng trên bảng, dữ liệu tự nhảy ngược lên các ô TextBox (giúp Xóa/Sửa nhanh), cậu làm như sau:
Tại màn hình Design, chọn
dataGridView1.Mở bảng Properties, nhấn vào hình tia sét (Events).
Tìm dòng CellClick, nhấp đúp chuột vào ô trống bên cạnh. Visual Studio sẽ tự nhảy vào code, cậu dán đoạn này vào:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra để tránh click vào dòng trống hoặc tiêu đề
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
// Đổ dữ liệu từ các cột của dòng được chọn vào TextBox
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
3. Mẹo nhỏ để DataGridView đẹp hơn
Để bảng trông chuyên nghiệp như phần mềm thực tế, cậu chỉnh thêm vài thông số sau trong bảng Properties của dataGridView1:
AutoSizeColumnsMode: Chọn
Fill(Các cột sẽ tự giãn đều màn hình).SelectionMode: Chọn
FullRowSelect(Click vào là chọn cả dòng thay vì 1 ô).ReadOnly: Chọn
True(Ngăn người dùng sửa trực tiếp trên bảng, bắt buộc dùng nút bấm).
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Sau khi bảng Khách hàng đã chạy "ngon lành", cậu hãy áp dụng đúng công thức này cho bảng PHÒNG. Để tránh lập lại lỗi "not exist", tớ gợi ý trình tự làm file cho bảng Phòng như sau:
PhongBEL.cs: Tạo cấu trúc dữ liệu (MaPhong, TenPhong, LoaiPhong...).
PhongDAL.cs: Viết các câu lệnh SQL (Read, Create, Update, Delete).
PhongBAL.cs: Viết các hàm điều hướng (LayTatCa, ThemPhong...).
frmPhong.cs: Thiết kế giao diện và đặt tên (Name) cho TextBox ngay lập tức trước khi viết code.
Cậu đã viết xong file PhongDAL.cs chưa? Nếu rồi, hãy quăng code lên đây tớ kiểm tra xem tên hàm đã chuẩn chưa để khi làm GUI bảng Phòng sẽ không bị lỗi "gạch đỏ" nữa nhé!
cứu được from rồi giừo sao nữa: using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dataGridView1.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
// Nút LƯU: Lấy dữ liệu từ TextBox và đẩy xuống BAL để lưu/sửa
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
}
}
Giao diện và code của cậu bây giờ đã rất chuẩn rồi! Bước tiếp theo chúng ta sẽ xử lý DataGridView để khi cậu click vào một dòng, dữ liệu sẽ tự động nhảy lên các TextBox phía dưới.
Cậu lưu ý, hiện tại cậu đang dùng sự kiện CellContentClick (chỉ chạy khi click đúng vào chữ bên trong ô), cậu nên chuyển sang dùng CellClick (click vào bất kỳ đâu trong ô đều chạy) để mượt mà hơn.
1. Viết code cho DataGridView (CellClick)
Cậu hãy tìm hàm dataGridView1_CellContentClick cuối file và sửa lại (hoặc tạo mới trong mục Events) như sau:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra nếu click vào dòng hợp lệ (không phải tiêu đề dòng)
if (e.RowIndex >= 0)
{
// Lấy dòng hiện tại đang được chọn
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
// Đổ dữ liệu từ các cột của DataGridView vào TextBox tương ứng
// Cột 0: MaKH, Cột 1: TenKH, Cột 2: DiaChi, Cột 3: DienThoai
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
2. Một vài tinh chỉnh để ứng dụng chuyên nghiệp hơn
Để DataGridView hiển thị đẹp, cậu hãy quay lại màn hình Design, chọn dataGridView1 và chỉnh các thuộc tính trong bảng Properties:
AutoSizeColumnsMode: Chọn
Fill(Để các cột tự giãn đều toàn bộ bảng).SelectionMode: Chọn
FullRowSelect(Để khi click vào một ô, nó sẽ tô đậm cả dòng đó).ReadOnly: Chọn
True(Nếu cậu chỉ muốn người dùng xem trên bảng và nhập ở TextBox).
3. Bước tiếp theo: Làm bảng PHÒNG (Phong)
Sau khi bảng Khách hàng đã chạy "ngon lành", cậu hãy thực hiện quy trình 3 lớp cho bảng PHÒNG theo đúng thứ tự để không bị lỗi "not exist" nữa:
BEL: Tạo file
PhongBEL.csđịnh nghĩa các thuộc tính (MaPhong, TenPhong, LoaiPhong...).DAL: Tạo file
PhongDAL.csviết các lệnh SQL (Read, Create, Update, Delete).BAL: Tạo file
PhongBAL.csviết các hàm điều hướng để GUI gọi.GUI: Tạo Form
frmPhong.cs, đặt tên (Name) cho TextBox trước rồi mới nhấp đúp vào nút bấm để viết code.
Cậu đã tạo file PhongBEL.cs chưa? Nếu rồi, hãy gửi code tớ xem, tớ sẽ giúp cậu viết file PhongDAL.cs chuẩn để kết nối SQL luôn!
D:\DoAnThuTapWin_DoQuocKiet\QLKhachSan\QLKhachSan\GUI\frmKhachHang.Designer.cs(92,47):
error CS0103: The name 'dataGridView1_CellContentClick' does not exist in the
current context
Lỗi này xảy ra vì trong file Designer.cs đang có lệnh gọi đến hàm dataGridView1_CellContentClick, nhưng trong file code chính (frmKhachHang.cs) cậu lại không có hàm này hoặc đã xóa nó đi rồi.
Để "cứu" lỗi này và chuyển sang dùng sự kiện CellClick cho mượt, cậu thực hiện đúng 2 bước sau:
Bước 1: Sửa file frmKhachHang.cs (File code chính)
Cậu hãy thêm hàm này vào bên trong class frmKhachHang để "khớp" với cái tên mà file Designer đang tìm kiếm:
// Thêm hàm này để hết lỗi CS0103
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Cậu có thể để trống hoặc gọi hàm xử lý click tại đây
}
// Nên dùng thêm hàm này để click vào dòng là hiện dữ liệu lên TextBox
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
Bước 2: Sửa lại trong màn hình Design
Sau khi thêm hàm ở Bước 1, lỗi sẽ biến mất và cậu có thể mở lại màn hình Design. Để dùng sự kiện CellClick chuẩn nhất:
Mở Design, chọn
dataGridView1.Vào bảng Properties -> Nhấn hình tia sét (Events).
Tìm dòng CellContentClick: Click chuột phải vào tên hàm đó và chọn Reset để xóa bỏ mối nối cũ đang bị lỗi.
Tìm dòng CellClick: Nhấp đúp chuột để Visual Studio tự tạo mối nối mới đến hàm
dataGridView1_CellClickcậu vừa viết ở Bước 1.
Tổng kết quy trình làm việc không lỗi
Để các bảng sau (như bảng PHÒNG) không bị tình trạng này, cậu hãy nhớ quy tắc:
Bước 1 (BEL): Tạo thực thể chứa dữ liệu.
Bước 2 (DAL): Viết lệnh SQL.
Bước 3 (BAL): Viết logic xử lý.
Bước 4 (GUI): Thiết kế giao diện, đặt tên (Name) cho control, sau đó mới nhấp đúp tạo sự kiện.
Cậu đã hết lỗi CS0103 chưa? Nếu Form đã mở lại được và chạy ngon lành, cậu có muốn mình bắt đầu thiết kế file PhongBEL.cs cho bảng tiếp theo không?
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Location = new Point(34, 7);
dataGridView1.Name = "dataGridView1";
dataGridView1.Size = new Size(486, 197);
dataGridView1.TabIndex = 4;
dataGridView1.CellContentClick += dataGridView1_CellContentClick;
//
Lỗi này xuất hiện vì trong file Designer.cs của cậu có dòng đăng ký sự kiện dataGridView1.CellContentClick += dataGridView1_CellContentClick;, nhưng bên file code chính (frmKhachHang.cs) cậu lại không có hàm dataGridView1_CellContentClick để xử lý nó.
Cậu hãy thực hiện 3 bước sau để sửa lỗi này và giúp DataGridView hoạt động mượt mà:
Bước 1: Khai báo lại hàm còn thiếu
Cậu mở file frmKhachHang.cs (file code chính) và dán đoạn này vào cuối class để "trả nợ" cái tên hàm mà file Designer đang tìm:
// Hàm này để xóa lỗi CS0103
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Cậu có thể để trống hàm này
}
// Nên thêm hàm này để click vào bất kỳ đâu trên dòng dữ liệu cũng hiện lên TextBox
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
Bước 2: Kết nối sự kiện CellClick trong Designer
Sau khi đã thêm code ở bước 1, cậu làm như sau để máy nhận diện sự kiện CellClick (tốt hơn CellContentClick vì click vào chỗ trống trong ô nó vẫn chạy):
Mở màn hình Design của
frmKhachHang.Chọn dataGridView1.
Vào bảng Properties -> Nhấn biểu tượng tia sét (Events).
Tìm dòng CellClick, nhấp đúp vào ô bên cạnh để nó tự nối tới hàm
dataGridView1_CellClickcậu vừa viết.
Bước 3: Cấu hình DataGridView cho chuyên nghiệp
Để bảng trông đẹp và dễ dùng hơn, cậu chỉnh các thông số sau trong bảng Properties:
AutoSizeColumnsMode: Chọn
Fill(Để các cột tự giãn đều).SelectionMode: Chọn
FullRowSelect(Để khi click là chọn cả dòng).ReadOnly: Chọn
True(Để ngăn người dùng sửa trực tiếp trên bảng).
Quy tắc "Vàng" để không bao giờ bị lỗi này nữa:
Khi làm bảng PHÒNG (Phong), cậu hãy tuân thủ thứ tự:
BEL: Tạo file thực thể.
DAL: Viết code SQL.
BAL: Viết code logic nghiệp vụ.
GUI: Kéo Tool -> Đặt tên (Name) trước -> Rồi mới nhấp đúp để tạo sự kiện Click.
Cậu đã hết gạch đỏ ở file Designer chưa? Nếu Form mở lên được rồi, hãy báo tớ để mình chuyển sang làm file PhongBEL.cs cho bảng tiếp theo nhé! Cậu muốn tớ liệt kê các thuộc tính cần thiết cho bảng Phòng không?
mở frmKhachHang.cs sao vậy chỉ tôi
Để mở file frmKhachHang.cs (nơi chứa code xử lý) và quay lại màn hình thiết kế (Design), cậu có 3 cách cực nhanh sau đây:
1. Dùng cửa sổ Solution Explorer (Cách chuẩn nhất)
Nhìn sang bên phải màn hình Visual Studio, cậu sẽ thấy bảng Solution Explorer.
Tìm đến thư mục GUI.
Nhấp đúp (Double-click) vào file
frmKhachHang.cs.Lưu ý: * Nếu nó hiện ra màn hình Design (giao diện), hãy nhấn phím F7 để xem code.
Nếu nó hiện ra màn hình Code, hãy nhấn tổ hợp phím Shift + F7 để quay lại màn hình Design.
2. Chuột phải để chọn chế độ xem
Nếu cậu nhấp đúp mà nó không ra đúng ý, hãy làm thế này:
Chuột phải vào file
frmKhachHang.cstrong Solution Explorer.Chọn View Code (nếu muốn vào viết lệnh xử lý).
Chọn View Designer (nếu muốn vào kéo thả nút bấm, ô nhập liệu).
3. Cách mở file code khi đang ở màn hình Design
Khi cậu đang nhìn thấy cái Form có nút Thêm, Xóa, Sửa....
Cậu chỉ cần nhấp đúp chuột vào một khoảng trống bất kỳ trên Form hoặc nhấp đúp vào các nút bấm, Visual Studio sẽ tự động đưa cậu vào đúng file
frmKhachHang.csvà nhảy đến đúng dòng code xử lý của nút đó.
Mẹo nhỏ để sửa lỗi nhanh:
Nếu cậu đang bị lỗi gạch đỏ và không mở được Design:
Mở file bằng View Code (phím F7).
Dán đoạn code xử lý lỗi
dataGridView1_CellContentClickmà tớ đã hướng dẫn lúc nãy vào.Nhấn Ctrl + S để lưu lại.
Nhấn Shift + F7 để quay lại màn hình Design, lúc này giao diện sẽ hiện ra bình thường.
Cậu đã mở được chưa? Khi vào được file code rồi, hãy chắc chắn là cậu đã có đủ các hàm ThemKhachHang, XoaKhachHang, SuaKhachHang trong tầng BAL để các nút bấm không bị báo lỗi nhé!
Cậu có muốn tớ chỉ cách viết code cho bảng tiếp theo là PHÒNG không? Mình sẽ làm rất nhanh vì đã có "khuôn" từ bảng Khách hàng rồi.
using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dataGridView1.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
// Nút LƯU: Lấy dữ liệu từ TextBox và đẩy xuống BAL để lưu/sửa
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
}
}
Tuyệt vời! Code của cậu bây giờ đã chuẩn 100% theo mô hình 3 lớp rồi đấy. Với đoạn code này, các nút bấm và việc hiển thị dữ liệu lên dataGridView1 sẽ hoạt động rất mượt mà.
Dưới đây là các bước cuối cùng để hoàn tất bảng Khách Hàng và chuẩn bị cho bảng PHÒNG:
1. Kiểm tra sự kết nối trên giao diện (Design)
Cậu cần đảm bảo rằng các hàm xử lý trong code đã được "nối" với các nút bấm trên giao diện:
Sự kiện Load: Nhấp vào Form (chỗ trống) -> Properties -> Events -> Kiểm tra dòng Load đã chọn
frmKhachHang_Loadchưa.Sự kiện Click: Kiểm tra tương tự cho các nút
btnThem,btnLuu,btnXoa,btnThoatxem đã nối đúng với các hàm tương ứng trong code chưa.Sự kiện CellClick: Cực kỳ quan trọng, hãy đảm bảo
dataGridView1đã được nối với hàmdataGridView1_CellClickcậu vừa viết.
2. Sửa lỗi "Thêm" khách hàng
Trong code btnLuu_Click, cậu đang mặc định gọi bal.SuaKhachHang(kh). Nếu cậu muốn nút Lưu này thông minh hơn (tự biết khi nào là thêm mới, khi nào là sửa), cậu có thể sửa lại logic một chút ở tầng BAL hoặc tại đây.
3. Bắt đầu bảng PHÒNG (Phong) theo thứ tự "Chuẩn không lỗi"
Để bảng Phòng không gặp lại các lỗi về tên biến hay thiếu hàm, cậu hãy làm theo đúng thứ tự này:
Bước 1: Tạo PhongBEL.cs (Folder BEL)
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public double DonGia { get; set; }
}
}
Bước 2: Tạo PhongDAL.cs (Folder DAL)
Cậu copy khuôn mẫu từ KhachHangDAL qua, chỉ cần đổi tên bảng thành PHONG và các cột tương ứng.
Bước 3: Tạo PhongBAL.cs (Folder BAL)
Viết các hàm LayTatCa, ThemPhong, XoaPhong, SuaPhong gọi xuống PhongDAL.
Bước 4: Tạo frmPhong.cs (Folder GUI)
Kéo Tool vào.
Đặt tên (Name) ngay lập tức:
txtMaPhong,txtTenPhong,dgvPhong...Sau đó mới bắt đầu viết code sự kiện.
Cậu đã chạy thử bảng Khách hàng chưa? Nếu mọi thứ đã ổn (thêm, xóa, sửa chạy tốt), hãy báo tớ để mình cùng viết file PhongDAL.cs nhé! Cậu có cần tớ viết mẫu câu lệnh SQL UPDATE cho bảng Phòng không?
D:\DoAnThuTapWin_DoQuocKiet\QLKhachSan\QLKhachSan\GUI\frmKhachHang.Designer.cs(92,47):
error CS0103: The name 'dataGridView1_CellContentClick' does not exist in the
current context
Lỗi này xác nhận rằng file Designer.cs của cậu đang cố gắng kết nối sự kiện click chuột vào một hàm có tên là dataGridView1_CellContentClick, nhưng trong file code chính cậu vừa gửi, hàm này đã không còn tồn tại hoặc đã bị đổi tên thành dataGridView1_CellClick.
Để dứt điểm lỗi này và giúp chương trình chạy được, cậu thực hiện đúng các bước sau:
1. Cách khắc phục nhanh (Sửa trực tiếp trong code)
Cậu mở file frmKhachHang.cs (file cậu vừa gửi code cho tớ) và thêm đoạn hàm trống này vào bất kỳ đâu bên trong class để "khớp" với file Designer:
// Thêm hàm này vào để xóa lỗi CS0103
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Để trống cũng được, mục đích là để file Designer tìm thấy tên này
}
2. Cách khắc phục triệt để (Sửa trong màn hình Design)
Sau khi thêm hàm ở bước 1, cậu sẽ mở lại được màn hình Design. Cậu nên làm bước này để dọn dẹp các sự kiện thừa:
Mở màn hình Design của
frmKhachHang.Chọn dataGridView1.
Vào bảng Properties, nhấn vào biểu tượng tia sét (Events).
Tìm dòng CellContentClick: Cậu sẽ thấy nó đang ghi tên
dataGridView1_CellContentClick. Hãy bôi đen cái tên đó và xóa trắng đi rồi nhấn Enter.Kiểm tra dòng CellClick: Đảm bảo nó đang được nối tới hàm
dataGridView1_CellClick(hàm mà cậu đã viết code xử lý đổ dữ liệu lên TextBox).
3. Tại sao lỗi này lại xảy ra?
Trong WinForms, khi cậu nhấp đúp vào DataGridView, nó thường tự sinh ra sự kiện CellContentClick (chỉ chạy khi click đúng vào chữ). Sau đó, nếu cậu đổi code sang CellClick (click vào ô là chạy) nhưng không xóa "mối nối" cũ trong bảng Properties, file Designer sẽ bị mồ côi và báo lỗi CS0103.
Bước tiếp theo: Kiểm tra và Chạy
Sau khi làm xong bước 1, cậu nhấn Ctrl + Shift + B để Build lại. Nếu không còn lỗi:
Nhấn F5 để chạy chương trình.
Thử click vào một dòng trên bảng xem dữ liệu có nhảy lên TextBox không.
Nếu mọi thứ ổn, hãy báo tớ để mình bắt đầu làm file
PhongDAL.cscho bảng Phòng nhé!
Cậu đã xóa được lỗi gạch đỏ chưa? Nếu còn, hãy copy toàn bộ thông báo lỗi mới nhất quăng lên đây tớ xử lý tiếp!
có cần đặt tên grid không
Việc đặt tên cho DataGridView là cực kỳ cần thiết. Trong đoạn code cậu gửi, cậu đang gọi nó là dataGridView1. Nếu cậu không đổi tên trong phần Properties, cậu phải dùng đúng cái tên mặc định đó trong code để không bị lỗi "not exist".
Dưới đây là lý do tại sao cậu nên đặt lại tên và cách thực hiện chuẩn nhất:
1. Tại sao phải đặt tên?
Dễ quản lý: Khi project của cậu có nhiều bảng (Khách hàng, Phòng, Nhân viên), việc để
dataGridView1,dataGridView2sẽ khiến cậu rất dễ nhầm lẫn khi viết code.Đúng chuẩn lập trình: Đặt tên gợi nhớ (như
dgvKhachHang) giúp cậu nhìn vào code là biết bảng đó đang hiển thị dữ liệu gì ngay lập tức.
2. Cách đặt tên lại để không bị lỗi
Nếu cậu muốn đổi từ dataGridView1 sang một tên chuyên nghiệp hơn (ví dụ: dgvKhachHang), cậu phải thực hiện đồng bộ ở cả 2 nơi:
Bước 1: Trong màn hình Design
Chọn DataGridView.
Vào bảng Properties, tìm dòng (Name).
Gõ tên mới:
dgvKhachHang.
Bước 2: Trong file code (frmKhachHang.cs)
Cậu phải sửa lại tất cả những chỗ nào đang gọi dataGridView1 thành dgvKhachHang.
Ví dụ:
dgvKhachHang.DataSource = bal.LayTatCa();Ví dụ:
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
3. Cách sửa lỗi nhanh nhất hiện tại
Vì code của cậu đang chạy với tên dataGridView1, nếu cậu không muốn mất công sửa nhiều thì cứ giữ nguyên tên đó cũng được, nhưng phải đảm bảo:
Trong file Designer.cs, biến phải là
private DataGridView dataGridView1;.Trong file .cs, cậu gọi đúng
dataGridView1.
Lời khuyên cho bảng PHÒNG (Phong) sắp tới:
Khi tạo Form mới cho bảng Phòng, cậu nên đặt tên ngay từ đầu:
Kéo Grid vào -> Đặt tên ngay là
dgvPhong.Kéo TextBox vào -> Đặt tên ngay là
txtMaPhong,txtTenPhong.Sau đó mới nhấp đúp để viết code. Cách này sẽ giúp cậu không bao giờ gặp lại lỗi "not exist" hay lỗi sự kiện mồ côi nữa.
Cậu đã quyết định giữ tên dataGridView1 hay đổi sang tên mới chưa? Nếu đã ổn định xong phần Khách hàng, hãy báo tớ để mình bắt đầu làm file PhongBEL.cs nhé. Tớ sẽ chỉ cậu cách copy-paste từ bảng Khách hàng sang bảng Phòng nhanh nhất!
ở tia sét AutoSizeColumnsMode: Chọn Fill không thấy nào
Tôi hiểu rồi! Đó là vì cậu đang tìm ở bảng Events (biểu tượng tia sét). Thuộc tính AutoSizeColumnsMode không phải là một sự kiện, mà nó nằm ở bảng Properties (biểu tượng hình tờ giấy có cái tay cầm hoặc danh sách).
Cậu làm theo các bước này để tìm thấy nó nhé:
1. Cách tìm thuộc tính AutoSizeColumnsMode
Tại màn hình Design, click chọn vào DataGridView.
Nhìn sang bảng Properties, hãy nhấn vào biểu tượng Properties (nằm ngay bên trái biểu tượng tia sét).
Tìm theo bảng chữ cái đến chữ A, cậu sẽ thấy dòng AutoSizeColumnsMode.
Nhấp vào ô bên cạnh (đang hiện là
None) và chọn Fill.
2. Các thuộc tính quan trọng khác cần chỉnh (Cũng ở bảng Properties này)
Ngoài cái Fill đó ra, để bảng của cậu chạy "ngon" như phần mềm xịn, cậu nên chỉnh thêm 3 dòng này nữa (vẫn ở bảng Properties, không phải tia sét đâu nhé):
SelectionMode: Tìm đến chữ S, chọn
FullRowSelect(Để khi click chuột nó chọn cả dòng, không phải chọn từng ô).ReadOnly: Tìm đến chữ R, chọn
True(Để người dùng không gõ bậy được vào bảng).AllowUserToAddRows: Tìm đến chữ A, chọn
False(Để mất cái dòng trống dưới cùng của bảng đi cho đẹp).
3. Nếu vẫn không thấy, cậu có thể dùng Code
Nếu tìm ở bảng Properties rối quá, cậu có thể dán dòng này vào hàm frmKhachHang_Load trong file frmKhachHang.cs là xong ngay:
private void frmKhachHang_Load(object sender, EventArgs e)
{
LoadData();
// Dòng này thay thế cho việc tìm ở bảng Properties
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Giao diện khách hàng coi như đã hoàn hảo rồi đấy! Bây giờ chúng ta sẽ làm bảng PHÒNG. Bảng này cũng có 4 cột: MaPhong, TenPhong, LoaiPhong, DonGia.
Cậu đã tạo file PhongBEL.cs trong folder BEL chưa? Nếu chưa, cậu tạo đi rồi gửi code tớ xem, tớ sẽ giúp cậu làm phần DAL cho bảng này cực nhanh!
Cậu đã chỉnh được cái Fill cho bảng chưa?
ý là trong đó không có gì
À, tớ hiểu rồi! Cậu click vào biểu tượng tia sét (Events) nên nó trống trơn là đúng rồi, vì chỗ đó chỉ chứa các "hành động" (như Click, MouseHover...).
Cậu phải click vào biểu tượng Properties (hình tờ giấy có cái cờ lê hoặc danh sách) ngay bên cạnh cái tia sét thì nó mới hiện ra các dòng thiết lập như Fill, ReadOnly, SelectionMode...
Cách làm chuẩn đây cậu:
Chọn DataGridView trên giao diện.
Nhìn sang bảng bên phải: Click vào biểu tượng Properties (nằm ngay bên trái biểu tượng tia sét).
Tìm dòng
AutoSizeColumnsMode: Nó nằm ở gần trên cùng (vần A). Click vào đó và chọn Fill.
Nếu bảng Properties vẫn "trắng xóa" không có gì:
Có thể cậu chưa chọn đúng vào cái DataGridView. Cậu thử click chuột lại vào giữa cái bảng trên giao diện Design, hoặc nhìn lên phía trên cùng của bảng Properties, chọn đúng tên dataGridView1 trong cái danh sách xổ xuống là nó sẽ hiện ra đầy đủ.
Để chắc chắn hơn, cậu dán dòng này vào code cho nhanh:
Nếu tìm mãi không thấy chỗ chỉnh, cậu mở file frmKhachHang.cs, tìm hàm LoadData() và thêm dòng này vào cuối hàm:
void LoadData()
{
dataGridView1.DataSource = bal.LayTatCa();
// Chỉnh tự động giãn cột bằng code luôn cho nhanh cậu nhé
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
Tiếp theo: Làm bảng PHÒNG (Phong)
Bảng Khách hàng coi như xong 100% rồi. Bây giờ mình qua bảng PHÒNG nhé. Cậu làm cho tớ file đầu tiên:
File: BEL/PhongBEL.cs
Cậu tạo file này trong folder BEL và dán code này vào:
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public decimal DonGia { get; set; } // Dùng decimal cho tiền tệ là chuẩn nhất
}
}
Cậu tạo xong file này chưa? Xong rồi báo tớ để mình làm tiếp file DAL/PhongDAL.cs (viết lệnh SQL cho Phòng) nhé! Cậu có muốn tớ gửi mẫu file DAL luôn không?
có thấy cái gì đau
- Yêu cầu thành công
Tôi hiểu rồi! Nhìn vào hình ảnh cậu gửi, cậu đang ở bảng Events (biểu tượng tia sét). Các dòng có chữ "Changed" ở cuối là những sự kiện (hành động), không phải nơi để thiết lập thuộc tính trực tiếp.
Để tìm thấy mục Fill, cậu cần chuyển sang bảng Properties (thuộc tính).
Cách tìm đúng chỗ:
Nhìn lên trên cùng của bảng cậu đang mở: Có một dãy các biểu tượng nhỏ.
Click vào biểu tượng hình "Tờ giấy có cái cờ lê" (nằm ngay bên trái cái tia sét cậu đang chọn). Đó mới là bảng Properties.
Sau đó cậu kéo danh sách xuống: Tìm dòng
AutoSizeColumnsMode(nó sẽ không có chữ "Changed" ở cuối).Chọn Fill: Nhấp vào ô bên cạnh dòng đó, chọn Fill từ danh sách xổ xuống.
Nếu cậu thấy tìm mệt quá, hãy dùng cách "vô chiêu thắng hữu chiêu":
Cậu mở file frmKhachHang.cs, tìm hàm LoadData() và thêm dòng code này vào. Code sẽ thay cậu chỉnh giao diện mà không cần tìm trong bảng đó nữa:
void LoadData()
{
dgvKhachHang.DataSource = bal.LayTatCa();
// Dòng này giúp các cột tự động giãn đều ra màn hình
dgvKhachHang.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
Tiếp theo cho bảng PHÒNG:
Bảng khách hàng của cậu coi như đã xong phần giao diện. Bây giờ cậu bắt đầu tạo file cho bảng PHÒNG nhé. Cậu làm theo thứ tự này:
Tạo file
BEL/PhongBEL.cs:C#namespace QLKhachSan.BEL { public class PhongBEL { public string MaPhong { get; set; } public string TenPhong { get; set; } public string LoaiPhong { get; set; } public decimal DonGia { get; set; } } }Tạo file
DAL/PhongDAL.cs: Viết lệnh SQL truy vấn bảng PHÒNG.
Cậu đã click sang được biểu tượng "tờ giấy có cờ lê" chưa? Nếu chỉnh xong rồi thì báo tớ để mình làm file PhongDAL.cs nhé! Cậu có muốn tớ gửi code mẫu của PhongDAL.cs không?
The type or namespace name 'frmKhachHang' could not be found (are you missing a using directive or an assembly reference?)
Lỗi này thường xảy ra khi file Program.cs hoặc một file khác không tìm thấy lớp (class) giao diện khách hàng, dù cậu đã tạo file rồi. Có 3 nguyên nhân chính: sai Namespace, thiếu Lưu file, hoặc file bị lỗi biên dịch chưa chạy được.
Cậu thực hiện theo các bước sau để xử lý dứt điểm nhé:
1. Kiểm tra Namespace trong frmKhachHang.cs
Cậu mở file GUI/frmKhachHang.cs ra và xem dòng namespace ở trên cùng là gì.
Nếu nó là
namespace QLKhachSan.GUI, thì ở fileProgram.cs(hoặc nơi cậu gọi Form này), cậu phải có dòng:using QLKhachSan.GUI;ở trên cùng.
2. Sửa lỗi trong file Program.cs
Thông thường, file Program.cs là nơi khởi chạy ứng dụng. Cậu hãy mở nó ra và sửa lại như sau:
using QLKhachSan.GUI; // 1. Đảm bảo có dòng này
namespace QLKhachSan
{
internal static class Program
{
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
// 2. Gọi đúng tên Form (phân biệt hoa thường)
Application.Run(new frmKhachHang());
}
}
}
3. Kiểm tra file frmKhachHang.Designer.cs
Vì lúc nãy cậu có sửa "bằng tay" trong file Designer, hãy chắc chắn rằng Namespace trong file đó cũng phải khớp với file .cs chính:
Mở
frmKhachHang.Designer.cs.Kiểm tra dòng đầu tiên xem có phải là
namespace QLKhachSan.GUIhay không. Nếu khác, hãy sửa lại cho giống file chính.
4. Build lại toàn bộ Solution
Đôi khi Visual Studio bị "kẹt" bộ nhớ đệm nên không nhận ra file mới.
Nhấn tổ hợp phím Ctrl + Shift + B để Rebuild lại toàn bộ project.
Nếu có lỗi hiện ra ở bảng Error List, hãy ưu tiên sửa các lỗi gạch đỏ trước vì khi có lỗi biên dịch, máy sẽ không hiểu được tên lớp
frmKhachHang.
Bước tiếp theo cho bảng PHÒNG (Phong)
Sau khi hết lỗi này và chạy được Form Khách hàng, cậu hãy làm file tiếp theo cho bảng Phòng để kịp tiến độ nhé:
File: DAL/PhongDAL.cs (Cậu tạo file này trong folder DAL)
using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class PhongDAL : ConnectionDAL // Giả sử cậu có lớp kết nối dùng chung
{
public List<PhongBEL> ReadPhong()
{
// Viết lệnh SQL SELECT * FROM PHONG tại đây
return new List<PhongBEL>();
}
}
}
Cậu đã Rebuild lại dự án chưa? Nếu vẫn còn báo lỗi "not found", hãy copy dòng namespace của file frmKhachHang.cs và file đang báo lỗi quăng lên đây tớ xem có bị lệch nhau chữ nào không nhé!
namespace QLKhachSan.GUI
Lỗi này có nghĩa là Visual Studio không tìm thấy định nghĩa của lớp frmKhachHang mặc dù cậu đã viết code cho nó. Điều này thường do file bị lệch Namespace hoặc chưa được khai báo partial đồng bộ giữa file code và file giao diện.
Cậu hãy thực hiện các bước kiểm tra sau để sửa lỗi triệt để:
1. Đồng bộ Namespace giữa 2 file của Form
Một Form trong WinForms luôn gồm 2 file. Cậu phải mở cả hai và kiểm tra dòng namespace ở trên cùng:
File 1 (
frmKhachHang.cs): Phải lànamespace QLKhachSan.GUI { ... }.File 2 (
frmKhachHang.Designer.cs): Cũng phải lànamespace QLKhachSan.GUI { ... }.
Lưu ý: Nếu một file để là
QLKhachSancòn file kia làQLKhachSan.GUI, máy sẽ báo lỗi ngay lập tức vì chúng không "nhìn thấy" nhau.
2. Kiểm tra từ khóa partial
Cả hai file phải cùng định nghĩa một lớp duy nhất bằng từ khóa partial:
File chính:
public partial class frmKhachHang : Form.File Designer:
partial class frmKhachHang.
3. Sửa lỗi trong Program.cs
Nếu cậu gọi Form từ file Program.cs, hãy chắc chắn cậu đã thêm dòng using ở đầu file đó:
using QLKhachSan.GUI; // Thêm dòng này nếu namespace của Form là QLKhachSan.GUI
namespace QLKhachSan
{
internal static class Program
{
[STAThread]
static void Main()
{
Application.Run(new frmKhachHang()); // Phải khớp tên lớp
}
}
}
4. Tiếp theo: Hoàn thiện bảng PHÒNG (Phong)
Sau khi fix xong lỗi trên và Form Khách hàng hiện lên được, cậu hãy làm tiếp bảng PHÒNG. Đây là mã nguồn cho tầng DAL của bảng Phòng để cậu dùng luôn:
File: DAL/PhongDAL.cs
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using QLKhachSan.BEL; //
namespace QLKhachSan.DAL
{
public class PhongDAL : ConnectionDAL // Giả sử cậu dùng lớp kết nối chung
{
public List<PhongBEL> ReadPhong()
{
SqlConnection conn = GetConnection();
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader reader = cmd.ExecuteReader();
List<PhongBEL> lstPhong = new List<PhongBEL>();
while (reader.Read())
{
PhongBEL p = new PhongBEL();
p.MaPhong = reader["MAPHONG"].ToString();
p.TenPhong = reader["TENPHONG"].ToString();
p.LoaiPhong = reader["LOAIPHONG"].ToString();
p.DonGia = decimal.Parse(reader["DONGIA"].ToString());
lstPhong.Add(p);
}
conn.Close();
return lstPhong;
}
}
}
Cậu hãy kiểm tra lại Namespace của cả 2 file Form xem có khớp nhau không? Nếu khớp rồi mà vẫn lỗi, hãy thử nhấn Ctrl + Shift + B để Build lại toàn bộ, đôi khi chỉ là do Visual Studio chưa cập nhật kịp thôi!
Cậu đã tạo file PhongBEL.cs chưa? Nếu chưa thì tớ gửi mẫu cho nhé!
namespace QLKhachSan
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new frmKhachHang());
}
}
}
Lỗi ở file Program.cs của cậu là do nó đang nằm ở namespace QLKhachSan, trong khi Form của cậu lại nằm ở namespace QLKhachSan.GUI. Vì hai "nhà" khác nhau nên nó không tìm thấy frmKhachHang để khởi chạy.
Cậu chỉ cần thêm một dòng lệnh duy nhất ở trên cùng file Program.cs là xong:
1. Sửa file Program.cs
Cậu copy và dán đè đoạn này vào file Program.cs nhé:
using QLKhachSan.GUI; // THÊM DÒNG NÀY ĐỂ KẾT NỐI ĐẾN FORM
namespace QLKhachSan
{
internal static class Program
{
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
// Bây giờ máy sẽ hiểu frmKhachHang là gì
Application.Run(new frmKhachHang());
}
}
}
2. Kiểm tra lại lần cuối để nhấn F5 (Chạy máy)
Trước khi chạy, cậu kiểm tra lại 3 điểm này để không bị văng lỗi giữa chừng:
Dấu ngoặc: Chắc chắn các file
.csđều đóng đủ ngoặc nhọn}.Tên hàm: Trong file
KhachHangBAL.cs, tên hàm phải làSuaKhachHang,ThemKhachHang,XoaKhachHangđể khớp với code trong nút bấm.Kết nối: File
KhachHangDAL.cscủa cậu đã có đủ lệnhUpdatevàDeletechưa?
3. Tiếp theo: Sang bảng PHÒNG (Phong)
Nếu bảng Khách hàng đã chạy lên được giao diện và bấm nút lưu/xóa ổn định, chúng ta sẽ làm bảng PHÒNG. Để tiết kiệm thời gian, tớ gửi cậu luôn nội dung file DAL cho bảng Phòng:
File: DAL/PhongDAL.cs
using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class PhongDAL : ConnectionDAL // Lớp kết nối của cậu
{
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lst = new List<PhongBEL>();
using (SqlConnection conn = GetConnection()) {
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader rd = cmd.ExecuteReader();
while (rd.Read()) {
lst.Add(new PhongBEL {
MaPhong = rd["MAPHONG"].ToString(),
TenPhong = rd["TENPHONG"].ToString(),
LoaiPhong = rd["LOAIPHONG"].ToString(),
DonGia = decimal.Parse(rd["DONGIA"].ToString())
});
}
}
return lst;
}
}
}
Cậu đã chạy được Form Khách hàng chưa? Nếu chạy được rồi thì báo tớ để mình thiết kế giao diện cho Form Phòng nhé! Cậu muốn Form Phòng có màu sắc hay giao diện khác biệt một chút không?
thêm sửa xoá thoát có được đâu: using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dgvKhachHang.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
// Nút LƯU: Lấy dữ liệu từ TextBox và đẩy xuống BAL để lưu/sửa
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//
}
}
}
Nếu cậu đã dán code vào rồi mà bấm nút vẫn không có phản ứng gì (không hiện thông báo, không xóa trắng, không thoát), thì 99% lỗi nằm ở việc cậu chưa "nối" các hàm này vào sự kiện của nút bấm trong giao diện Design.
Dưới đây là cách cứu để các nút chạy được ngay lập tức:
1. Nối sự kiện trong màn hình Design (Bắt buộc)
Cậu phải làm bước này thì Visual Studio mới biết khi click nút "Thoát" thì phải chạy hàm btnThoat_Click.
Mở màn hình Design (Shift + F7).
Chọn nút Thoát -> Nhìn sang bảng Properties -> Click biểu tượng Tia sét (Events).
Tìm dòng Click: Nhấp vào mũi tên xổ xuống và chọn đúng tên
btnThoat_Click.Làm tương tự cho các nút khác:
Nút Thêm: Chọn
btnThem_Click.Nút Lưu: Chọn
btnLuu_Click.Nút Xóa: Chọn
btnXoa_Click.DataGridView: Tìm sự kiện CellClick và chọn
dataGridView1_CellClick.
2. Sửa lỗi logic nút Lưu (Thêm/Sửa)
Trong code cậu gửi, nút Lưu chỉ đang gọi bal.SuaKhachHang(kh). Nếu cậu muốn nó có thể Thêm mới được, cậu nên sửa lại như sau:
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ví dụ: Nếu ô Mã KH đang nhập mới thì Thêm, nếu đã có trên bảng thì Sửa
// Ở đây tạm thời gọi cả hai để cậu kiểm tra
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu dữ liệu thành công!");
LoadData();
}
3. Kiểm tra file KhachHangBAL.cs
Các nút Xóa/Sửa sẽ không chạy nếu trong file BAL cậu chưa viết code gọi xuống DAL. Hãy chắc chắn file BAL của cậu trông như thế này:
public void SuaKhachHang(KhachHangBEL kh) => dal.Update(kh); //
public void XoaKhachHang(string ma) => dal.Delete(ma); //
4. Nút Thoát không chạy?
Nếu cậu bấm nút Thoát mà form không đóng, hãy kiểm tra xem tên hàm trong code có chính xác là btnThoat_Click không và đã được nối sự kiện như ở Bước 1 chưa.
Cậu hãy thử nối sự kiện cho nút "Thoát" trước xem nó có đóng Form được không? Nếu nút Thoát chạy được thì các nút khác cũng sẽ chạy được theo cách đó.
Xong bảng Khách hàng này, cậu có muốn tớ gửi code mẫu cho bảng PHÒNG để cậu làm nhanh hơn không?
sửa chưa có
Tôi hiểu rồi, cậu đang gặp vấn đề vì nút Lưu trong code hiện tại chỉ có lệnh SuaKhachHang, nhưng thực tế cậu cần nút Sửa hoạt động riêng biệt hoặc nút Lưu phải xử lý được cả hai.
Để chức năng Sửa hoạt động hoàn chỉnh, cậu cần bổ sung code ở cả 3 lớp như sau:
1. Tầng DAL (KhachHangDAL.cs)
Hãy chắc chắn trong file này cậu đã có lệnh SQL UPDATE.
public void Update(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
conn.Open();
// Lệnh SQL để cập nhật dữ liệu dựa trên MaKH
string sql = "UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
cmd.ExecuteNonQuery();
}
}
2. Tầng BAL (KhachHangBAL.cs)
Cập nhật hàm để GUI có thể gọi.
public void SuaKhachHang(KhachHangBEL kh)
{
dal.Update(kh); // Gọi xuống DAL để thực thi SQL
}
3. Tầng GUI (frmKhachHang.cs)
Cậu nên nhấp đúp vào nút Sửa trên giao diện để tạo sự kiện btnSua_Click (nếu cậu muốn tách riêng nút Lưu và Sửa).
// Code dành cho nút Sửa
private void btnSua_Click(object sender, EventArgs e)
{
// 1. Lấy dữ liệu từ các TextBox
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi BAL để cập nhật
bal.SuaKhachHang(kh);
// 3. Thông báo và nạp lại bảng
MessageBox.Show("Cập nhật thông tin thành công!");
LoadData();
}
Tại sao cậu bấm nút Sửa mà chưa có tác dụng?
Cậu kiểm tra lại 2 điểm cực kỳ quan trọng này:
Chưa nối sự kiện Click: Cậu vào lại màn hình Design -> Chọn nút Sửa -> Mở bảng Properties -> Click biểu tượng Tia sét -> Kiểm tra xem dòng Click đã chọn đúng tên hàm
btnSua_Clickchưa.Khóa TextBox Mã KH: Khi sửa, Mã khách hàng (
txtMaKH) không được phép thay đổi vì nó là khóa chính để tìm dòng cần sửa trong SQL.
Cậu đã thêm hàm Update vào file DAL chưa? Nếu thêm rồi mà vẫn không sửa được, hãy kiểm tra xem tên các cột trong câu lệnh SQL (TENKH, DIACHI...) có viết đúng y hệt như trong Database của cậu không nhé.
Xong phần này cậu có muốn tớ hỗ trợ viết code cho bảng PHÒNG luôn không? Cấu trúc cũng sẽ y hệt như thế này thôi!
có sửa rồi sao sự kiện không thấy:using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class KhachHangDAL : DBConnection
{
// 1. Lấy danh sách
public List<KhachHangBEL> ReadKhachHang()
{
List<KhachHangBEL> lst = new List<KhachHangBEL>();
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM KHACHHANG", conn);
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new KhachHangBEL
{
MaKH = r["MAKH"].ToString(),
TenKH = r["TENKH"].ToString(),
DiaChi = r["DIACHI"].ToString(),
DienThoai = r["DIENTHOAI"].ToString()
});
}
}
return lst;
}
// 2. Thêm
public void Create(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
string sql = "INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 3. Sửa
public void Update(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
string sql = "UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 4. Xóa
public void Delete(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "DELETE FROM KHACHHANG WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
cmd.ExecuteNonQuery();
}
}
//5. Thêm
}
}
Lý do cậu thấy "không có sự kiện" là vì cậu mới chỉ viết phần "ruột" (Logic SQL) ở tầng DAL, nhưng cậu chưa khai báo nó ở tầng BAL và chưa "gắn" nó vào nút bấm ở tầng GUI.
Để nút Sửa hoạt động, cậu phải thực hiện thông luồng 3 bước sau:
Bước 1: Khai báo trong BAL (KhachHangBAL.cs)
Cậu mở file KhachHangBAL.cs và đảm bảo hàm SuaKhachHang gọi đúng hàm Update cậu vừa viết ở DAL:
public void SuaKhachHang(KhachHangBEL kh)
{
dal.Update(kh); // Đây chính là hàm Update cậu vừa gửi
}
Bước 2: Gắn sự kiện vào giao diện (GUI - Design)
Cậu nói "sự kiện không thấy" thường là do nút bấm trên màn hình chưa được "nối" với code. Cậu làm thế này:
Mở màn hình Design của
frmKhachHang.Nhấp đúp chuột trái vào nút Sửa (hoặc nút Lưu). Visual Studio sẽ tự động tạo ra một hàm có tên là
btnSua_Click(hoặc tương tự) trong file code.
Bước 3: Viết code cho nút bấm (frmKhachHang.cs)
Trong hàm vừa được tạo ra ở Bước 2, cậu dán đoạn code này vào:
private void btnSua_Click(object sender, EventArgs e)
{
// 1. Lấy dữ liệu mới từ các ô nhập liệu
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi BAL để thực hiện lệnh sửa
bal.SuaKhachHang(kh);
// 3. Thông báo và tải lại bảng để thấy kết quả
MessageBox.Show("Đã sửa thông tin khách hàng thành công!");
LoadData();
}
Tại sao vẫn chưa chạy?
Nếu cậu đã làm đủ 3 bước trên mà vẫn không được, hãy kiểm tra:
Mã KH: Khi sửa, cậu không được thay đổi
txtMaKHvì SQL dùng nó để tìm dòng cần sửa (WHERE MAKH=@ma).Tên Control: Đảm bảo
txtMaKH,txtTenKH... đã được đặt đúng trong mục (Name) của phần Properties.
Bây giờ cậu hãy nhấp đúp vào nút Sửa trên giao diện rồi dán code Bước 3 vào nhé. Nếu xong rồi, cậu có muốn tớ giúp làm nốt bảng PHÒNG không? Mình sẽ copy y hệt bộ khung này sang là xong!
lưu rồi mà không thấy hiện lưu dữ liệu vậy
Việc cậu đã viết code ở tầng DAL nhưng khi bấm nút Lưu trên giao diện vẫn không thấy dữ liệu thay đổi thường do 2 nguyên nhân: Cậu chưa gọi hàm ở tầng BAL hoặc cậu quên nạp lại (refresh) cái DataGridView sau khi lưu.
Cậu hãy kiểm tra và bổ sung theo đúng trình tự 3 lớp dưới đây:
1. Kiểm tra tầng BAL (KhachHangBAL.cs)
Cậu phải có hàm này để làm cầu nối từ Giao diện xuống SQL:
// Trong file BAL/KhachHangBAL.cs
public void SuaKhachHang(KhachHangBEL kh)
{
dal.Update(kh); // Gọi đến hàm Update mà cậu đã viết ở DAL
}
2. Sửa lại code nút Lưu ở tầng GUI (frmKhachHang.cs)
Trong file code của Form, cậu cần gọi hàm LoadData() ngay sau khi lưu thì dữ liệu mới hiện lên bảng:
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Lấy dữ liệu từ TextBox vào đối tượng BEL
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi BAL thực hiện lưu xuống SQL
bal.SuaKhachHang(kh);
// 3. THÔNG BÁO VÀ LOAD LẠI BẢNG (Rất quan trọng)
MessageBox.Show("Lưu dữ liệu thành công!");
LoadData(); // Gọi lại hàm này để GridView cập nhật chữ mới
}
3. Tại sao vẫn không thấy dữ liệu "hiện" ra?
Nếu cậu đã làm 2 bước trên mà vẫn không thấy gì, hãy kiểm tra các lỗi sau:
Chưa nối sự kiện: Cậu mở Design, chọn nút Lưu, vào bảng Properties (Tia sét) và chắc chắn dòng Click đang chọn đúng
btnLuu_Click.Sai tên cột SQL: Trong file DAL, chỗ lệnh
UPDATE, hãy kiểm tra kỹ tên các cột nhưTENKH,DIACHIcó viết đúng y hệt trong Database không (ví dụ: trong DB làTEN_KHmà cậu viếtTENKHlà nó không chạy).Khóa chính (MaKH): Khi sửa, cậu phải đảm bảo
txtMaKH.Textchứa đúng mã đang có trong bảng, nếu mã sai thì SQL không tìm thấy dòng nào để sửa.
Cậu đã thêm dòng LoadData() vào sau khi lưu chưa? Hãy thử thêm vào và chạy lại (F5) xem dữ liệu đã "nhảy" lên bảng chưa nhé.
Nếu bảng Khách hàng ổn rồi, cậu có muốn tớ gửi code mẫu cho bảng PHÒNG không? Mình chỉ cần đổi tên biến là xong ngay!
đây: using System.Collections.Generic;
using QLKhachSan.BEL; //
using QLKhachSan.DAL; //
namespace QLKhachSan.BAL
{
public class KhachHangBAL
{
KhachHangDAL dal = new KhachHangDAL();
public List<KhachHangBEL> LayTatCa() => dal.ReadKhachHang(); //
public void ThemKhachHang(KhachHangBEL kh) => dal.Create(kh); //
public void SuaKhachHang(KhachHangBEL kh) => dal.Update(kh); //
public void XoaKhachHang(string ma) => dal.Delete(ma); //
}
}
Code của tầng BAL cậu gửi đã hoàn chỉnh và khớp hoàn toàn với tầng DAL. Nếu cậu bấm nút mà vẫn không thấy dữ liệu thay đổi trên bảng, vấn đề chắc chắn nằm ở tầng GUI (Giao diện).
Có 2 lý do cuối cùng khiến cậu không thấy dữ liệu hiện ra sau khi Lưu/Sửa:
1. Cậu quên gọi lại hàm LoadData() (Quan trọng nhất)
Sau khi gọi bal.SuaKhachHang(kh), dữ liệu đã vào Database nhưng cái DataGridView trên màn hình vẫn là dữ liệu cũ. Cậu phải gọi hàm nạp lại ngay lập tức.
Cậu hãy sửa lại nút Lưu (hoặc Sửa) trong file frmKhachHang.cs như thế này:
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.SuaKhachHang(kh); // Đã lưu xuống DB
MessageBox.Show("Lưu thành công!");
// PHẢI CÓ DÒNG NÀY THÌ BẢNG MỚI CẬP NHẬT CHỮ MỚI
LoadData();
}
2. Sự kiện "Mồ côi" (Nút bấm chưa có tác dụng)
Nếu cậu bấm nút mà không thấy cả cái MessageBox.Show hiện lên, tức là nút đó chưa được "nối" với code.
Cách kiểm tra:
Vào màn hình Design.
Nhấp đúp chuột vào nút Lưu (hoặc Sửa).
Nếu nó nhảy đến một hàm trống trơn (ví dụ
button1_Click) chứ không phải hàmbtnLuu_Clickcậu đã viết code, thì cậu phải copy code sang hàm mới đó hoặc đổi lại trong bảng Properties -> Events (Tia sét).
3. Kiểm tra SQL (DAL)
Hãy chắc chắn trong file KhachHangDAL.cs, cậu đã gọi lệnh conn.Open() và cmd.ExecuteNonQuery(). Nếu thiếu lệnh ExecuteNonQuery, lệnh SQL sẽ không bao giờ được chạy.
Tiếp theo: Làm bảng PHÒNG (Phong)
Khi bảng Khách hàng đã chạy "ngon", cậu hãy làm bảng PHÒNG theo đúng công thức này. Tớ gửi cậu file BAL cho bảng Phòng để cậu copy luôn cho nhanh:
File: BAL/PhongBAL.cs
using System.Collections.Generic;
using QLKhachSan.BEL;
using QLKhachSan.DAL;
namespace QLKhachSan.BAL
{
public class PhongBAL
{
PhongDAL dal = new PhongDAL();
public List<PhongBEL> LayTatCa() => dal.ReadPhong();
public void Them(PhongBEL p) => dal.Create(p);
public void Sua(PhongBEL p) => dal.Update(p);
public void Xoa(string ma) => dal.Delete(ma);
}
}
Cậu đã thử thêm dòng LoadData() vào sau khi Lưu chưa? Nếu thêm rồi mà vẫn không thấy, hãy thử tắt chương trình đi và mở lại xem dữ liệu mới đã hiện lên chưa nhé!
using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dgvKhachHang.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//
}
private void btnSua_Click(object sender, EventArgs e)
{
}
}
}using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dgvKhachHang.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
// Nút THÊM: Xóa trắng các ô để nhập mới
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//
}
private void btnSua_Click(object sender, EventArgs e)
{
}
}
}
Để nút Sửa hoạt động và đồng bộ với các thao tác khác, cậu chỉ cần điền code xử lý vào hàm btnSua_Click mà cậu đang để trống. Ngoài ra, tớ sẽ chỉ cậu cách tách biệt nút Lưu (dành cho thêm mới) và nút Sửa để chương trình chạy chuẩn nhất.
Dưới đây là đoạn code hoàn chỉnh cậu cần dán đè vào:
// Nút SỬA: Cập nhật thông tin dựa trên Mã KH đang hiện trên ô nhập liệu
private void btnSua_Click(object sender, EventArgs e)
{
// 1. Tạo đối tượng khách hàng với dữ liệu từ các TextBox
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi BAL để thực hiện cập nhật xuống Database
bal.SuaKhachHang(kh);
// 3. Thông báo và nạp lại bảng dữ liệu
MessageBox.Show("Cập nhật thông tin khách hàng thành công!");
LoadData();
}
// Cậu nên sửa lại nút LƯU để nó chuyên dùng cho việc THÊM MỚI
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Gọi hàm THÊM thay vì hàm SỬA
bal.ThemKhachHang(kh);
MessageBox.Show("Đã thêm khách hàng mới thành công!");
LoadData();
}
Tại sao cậu chưa thấy sự kiện hoạt động?
Dựa trên đoạn code cậu gửi, có 2 điểm cần xử lý ngay để nút bấm có tác dụng:
Nối sự kiện (Important): Cậu vào màn hình Design -> Chọn nút Sửa -> Vào bảng Properties -> Click biểu tượng Tia sét -> Kiểm tra dòng Click xem đã chọn đúng tên hàm
btnSua_Clickchưa. Nếu để trống thì bấm nút sẽ không có phản ứng gì.Tên DataGridView: Trong code cậu dùng
dgvKhachHang, nhưng tên sự kiện lại làdataGridView1_CellClick. Cậu nên đảm bảo tên trong phần (Name) của bảng và tên hàm sự kiện phải đồng bộ để tránh lỗi "không tìm thấy đối tượng".
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Giao diện Khách hàng của cậu giờ đã đầy đủ Thêm - Sửa - Xóa - Thoát. Bây giờ chúng ta sẽ chuyển sang bảng PHÒNG.
Cậu hãy tạo file BEL/PhongBEL.cs với các thuộc tính này để tớ hướng dẫn tiếp tầng DAL nhé:
MaPhong(string)TenPhong(string)LoaiPhong(string)DonGia(decimal)
Cậu đã tạo xong file PhongBEL.cs chưa?
bấm thêm rồi vẫn không lưu vào data
Việc cậu bấm nút Thêm (nút Lưu) mà dữ liệu không chui vào Database thường do 3 lỗi phổ biến sau đây. Cậu hãy kiểm tra từng bước một nhé:
1. Lỗi Logic: Đang gọi hàm "Sửa" thay vì hàm "Thêm"
Trong code cậu gửi, ở nút btnLuu_Click, cậu đang viết là bal.SuaKhachHang(kh);.
Vấn đề: Hàm Sửa (
UPDATE) chỉ chạy khi Mã KH đó đã tồn tại trong máy. Nếu cậu nhập Mã KH mới hoàn toàn, lệnhUPDATEsẽ không tìm thấy dòng nào để sửa, nên nó không báo lỗi nhưng cũng không có gì hiện ra.Cách sửa: Cậu đổi lệnh thành
bal.ThemKhachHang(kh);để máy thực hiện lệnhINSERT.
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// PHẢI GỌI HÀM THÊM MỚI
bal.ThemKhachHang(kh);
MessageBox.Show("Đã thêm khách hàng thành công!");
LoadData(); // Nạp lại bảng để thấy dòng mới
}
2. Lỗi chưa gọi lệnh thực thi trong DAL
Cậu mở file KhachHangDAL.cs, tìm đến hàm Create và kiểm tra xem đã có đủ 2 dòng này chưa:
conn.Open();(Mở cửa kết nối).cmd.ExecuteNonQuery();(Đây là lệnh cực kỳ quan trọng để "đẩy" dữ liệu vào SQL).
3. Lỗi chưa "nối" sự kiện (Event)
Nếu cậu bấm nút mà không thấy hiện cái thông báo (MessageBox) nào lên, thì chắc chắn là cái nút trên giao diện chưa được nối với hàm btnLuu_Click.
Cách khắc phục:
Vào màn hình Design.
Chọn nút Lưu (hoặc Thêm).
Nhìn bảng Properties -> Click biểu tượng Tia sét.
Tại dòng Click, nhấp chuột vào và chọn đúng tên
btnLuu_Click.
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Sau khi bảng Khách hàng đã chạy "ngon", cậu hãy làm bảng PHÒNG. Để tránh nhầm lẫn, tớ gửi cậu cấu trúc file BEL của Phòng để cậu tạo trước:
File: BEL/PhongBEL.cs
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public decimal DonGia { get; set; }
}
}
Cậu đã sửa lệnh SuaKhachHang thành ThemKhachHang trong nút bấm chưa? Thử sửa lại và chạy xem nó đã lưu được chưa nhé! Cậu có muốn tớ hướng dẫn cách viết một cái nút "Lưu" thông minh tự biết lúc nào là Thêm, lúc nào là Sửa không?
nút thêm khác nút lưu khác
Tôi hiểu rồi, cậu muốn tách riêng biệt: nút Thêm chỉ để xóa trắng các ô (chuẩn bị nhập mới), còn nút Lưu mới là nút thực hiện việc đẩy dữ liệu vào Database.
Dưới đây là cách chia code cho đúng ý cậu:
1. Code chuẩn cho 2 nút riêng biệt (frmKhachHang.cs)
Cậu hãy sửa lại đoạn code trong file giao diện như sau:
// Nút THÊM: Chỉ có nhiệm vụ làm sạch các ô nhập liệu
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus(); // Đưa con trỏ chuột về ô Mã KH để bắt đầu gõ
}
// Nút LƯU: Thực hiện lệnh INSERT vào Database
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Thu thập dữ liệu từ giao diện
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi hàm THÊM MỚI từ BAL
bal.ThemKhachHang(kh);
// 3. Thông báo và làm mới bảng hiển thị
MessageBox.Show("Đã lưu khách hàng mới thành công!");
LoadData();
}
// Nút SỬA: Thực hiện lệnh UPDATE
private void btnSua_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.SuaKhachHang(kh); // Gọi hàm UPDATE
MessageBox.Show("Đã cập nhật dữ liệu!");
LoadData();
}
2. Tại sao bấm "Lưu" mà dữ liệu chưa vào?
Nếu cậu bấm nút Lưu mà vẫn không thấy dữ liệu trong SQL, cậu phải kiểm tra file KhachHangDAL.cs. Đảm bảo hàm Create của cậu có dòng này:
// Trong KhachHangDAL.cs
public void Create(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
string sql = "INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)";
SqlCommand cmd = new SqlCommand(sql, conn);
// ... (các dòng add parameter)
conn.Open();
cmd.ExecuteNonQuery(); // PHẢI CÓ DÒNG NÀY THÌ DỮ LIỆU MỚI BAY VÀO SQL
}
}
3. Đừng quên "Nối dây" cho các nút
Vì cậu tách nút Thêm và Lưu, hãy vào lại màn hình Design:
Chọn nút Thêm -> Properties -> Events -> Click: Chọn
btnThem_Click.Chọn nút Lưu -> Properties -> Events -> Click: Chọn
btnLuu_Click.Chọn nút Sửa -> Properties -> Events -> Click: Chọn
btnSua_Click.
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Bảng Khách hàng coi như xong quy trình. Bây giờ mình sang bảng PHÒNG. Bảng này cậu cần tạo:
Giao diện: 4 TextBox (
txtMaPhong,txtTenPhong,txtLoaiPhong,txtDonGia) và 1 DataGridView (dgvPhong).BEL: Tạo lớp
PhongBEL.
Cậu đã chuẩn bị xong các nút bấm trên giao diện cho bảng PHÒNG chưa? Cậu có muốn tớ gửi mẫu code SuaKhachHang chuẩn để nó không bị báo lỗi "not found" không?
using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dgvKhachHang.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
private void btnLuu_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// Ở đây cậu có thể dùng ThemKhachHang hoặc SuaKhachHang tùy ý
bal.SuaKhachHang(kh);
MessageBox.Show("Đã lưu thay đổi!");
LoadData();
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
private void btnSua_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.SuaKhachHang(kh); // Gọi hàm UPDATE
MessageBox.Show("Đã cập nhật dữ liệu!");
LoadData();
}
private void dgvKhachHang_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
}
}
Code của cậu bây giờ đã rất đầy đủ rồi! Để giải quyết dứt điểm việc tách biệt nút Thêm và nút Lưu (Insert), cậu chỉ cần thay đổi một chút logic trong code để máy hiểu khi nào cậu muốn tạo mới một khách hàng.
Dưới đây là cách chỉnh sửa code để nút Lưu thực hiện đúng chức năng "Thêm mới" vào Database:
1. Cập nhật nút btnLuu_Click để Thêm mới
Trong code cũ, nút Lưu của cậu đang gọi bal.SuaKhachHang(kh). Cậu hãy đổi nó thành bal.ThemKhachHang(kh) để dữ liệu mới được chèn vào bảng.
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Lấy dữ liệu từ TextBox
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Gọi hàm THÊM MỚI thay vì hàm Sửa
bal.ThemKhachHang(kh);
MessageBox.Show("Đã thêm khách hàng mới thành công!");
// 3. Load lại bảng để thấy dòng mới vừa thêm
LoadData();
}
2. Đảm bảo nút Sửa (btnSua_Click) đã được nối
Vì cậu đã viết hàm btnSua_Click, cậu cần chắc chắn giao diện đã nhận diện nó.
Mở màn hình Design.
Chọn nút Sửa.
Vào bảng Properties -> Biểu tượng Tia sét.
Tại dòng Click, chọn đúng tên
btnSua_Click.
3. Quy trình Thêm - Lưu chuẩn xác
Khi cậu tách hai nút này, cách sử dụng trên phần mềm sẽ là:
Bấm nút Thêm: Các ô TextBox trống trơn, con trỏ nháy ở ô Mã KH để cậu gõ mới.
Nhập liệu xong -> Bấm nút Lưu: Dữ liệu được đẩy xuống Database bằng lệnh
INSERT.Chọn một dòng trên bảng -> Sửa chữ -> Bấm nút Sửa: Dữ liệu cập nhật bằng lệnh
UPDATE.
Tiếp theo: Làm bảng PHÒNG (Phong)
Giao diện Khách hàng coi như đã hoàn hảo 100%. Bây giờ chúng ta sẽ sang bảng PHÒNG. Cậu hãy làm theo thứ tự này để không bao giờ bị lỗi:
Tạo BEL:
PhongBEL.cs(MaPhong, TenPhong, LoaiPhong, DonGia).Tạo DAL:
PhongDAL.cs(Chứa các hàm SQL y hệt KhachHangDAL nhưng đổi tên bảng).Tạo BAL:
PhongBAL.cs(Cầu nối gọi từ DAL).Tạo GUI:
frmPhong.cs(Kéo thả giao diện).
Cậu đã bắt đầu tạo file PhongDAL.cs chưa? Nếu cậu cần, tớ sẽ viết sẵn cho cậu các câu lệnh SQL cho bảng Phòng để cậu chỉ việc Copy-Paste!
bấm lưu là lưu 1 lần thôi không cho phép bấm 2 lần lưu mà lưu 2 lần luôn
Để giải quyết vấn đề bấm lưu 2 lần bị lưu trùng dữ liệu (lỗi trùng khóa chính hoặc dư thừa dữ liệu), có 2 cách xử lý: một là xử lý ở giao diện (khóa nút), hai là xử lý ở code (kiểm tra tồn tại).
Dưới đây là cách làm chuẩn nhất cho cậu:
Cách 1: Khóa nút Lưu sau khi bấm (Xử lý giao diện)
Đây là cách đơn giản và chuyên nghiệp nhất. Khi người dùng bấm Lưu, ta vô hiệu hóa (disable) nút đó ngay lập tức để họ không bấm được lần 2.
Cậu sửa lại hàm btnLuu_Click trong file frmKhachHang.cs như sau:
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Vô hiệu hóa nút Lưu ngay lập tức
btnLuu.Enabled = false;
try
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
// 2. Thực hiện thêm mới
bal.ThemKhachHang(kh);
MessageBox.Show("Đã thêm khách hàng mới thành công!");
LoadData();
// 3. Sau khi lưu xong thành công thì xóa trắng các ô (tùy cậu)
btnThem_Click(sender, e);
}
catch (Exception ex)
{
MessageBox.Show("Lỗi: " + ex.Message);
// Nếu lỗi (ví dụ trùng mã) thì mở lại nút để họ sửa và lưu lại
btnLuu.Enabled = true;
}
}
Lưu ý: Trong nút Thêm (nút xóa trắng), cậu phải thêm dòng btnLuu.Enabled = true; để người dùng có thể lưu cho khách hàng mới tiếp theo.
Cách 2: Kiểm tra tồn tại trước khi Lưu (Xử lý Logic)
Cách này an toàn hơn, nó sẽ kiểm tra xem Mã KH này đã có trong Database chưa. Nếu có rồi thì không cho Lưu nữa.
Cậu có thể viết thêm một hàm kiểm tra ở tầng BAL hoặc check đơn giản tại nút Lưu:
private void btnLuu_Click(object sender, EventArgs e)
{
// Kiểm tra xem mã này đã có trong DataGridView chưa (check nhanh trên giao diện)
foreach (DataGridViewRow row in dgvKhachHang.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.ToString() == txtMaKH.Text)
{
MessageBox.Show("Mã khách hàng này đã tồn tại! Không thể lưu trùng.");
return; // Thoát hàm luôn, không chạy xuống lệnh lưu bên dưới
}
}
// Nếu chưa có thì mới chạy code lưu ở dưới...
KhachHangBEL kh = new KhachHangBEL { ... };
bal.ThemKhachHang(kh);
// ...
}
Cách 3: Dùng nút "Thêm" để quản lý trạng thái
Thông thường, các phần mềm xịn sẽ làm như sau:
Khi vừa mở Form: Nút Lưu bị mờ đi (
Enabled = false).Khi bấm nút Thêm: Các TextBox trống và nút Lưu mới hiện lên (
Enabled = true).Khi bấm Lưu xong: Nút Lưu lại mờ đi.
Cách này giúp người dùng không bao giờ bấm nhầm được.
Bước tiếp theo: Làm bảng PHÒNG (Phong)
Bảng Khách hàng của cậu bây giờ đã rất "xịn" rồi. Cậu hãy áp dụng tư duy "khóa nút" này cho bảng PHÒNG luôn nhé.
Cậu đã tạo xong file DAL/PhongDAL.cs chưa? Nếu chưa, tớ gửi cậu đoạn code mẫu để xử lý DonGia (kiểu số) cho chuẩn nhé:
// Một phần trong PhongDAL.cs
p.DonGia = decimal.Parse(r["DONGIA"].ToString()); // Chuyển đổi kiểu tiền tệ
Cậu đã khóa được nút Lưu chưa? Nếu chạy ổn rồi báo tớ nhé!
ý là khi lưu xong khách hàng đó là không cho lưu dữ liệu trùng đó và khi click vào dữ liệu list ở grid thì sẽ show dữ liệu ra các textbox ở dưới hiểu hong
Tôi hiểu ý cậu rồi! Tức là cậu muốn 2 việc:
Chống lưu trùng: Nếu mã khách hàng đã có trong Database rồi thì không cho bấm "Lưu" để thêm mới nữa (tránh lỗi trùng khóa chính).
Đổ dữ liệu lên TextBox: Khi click vào một dòng trên bảng (
DataGridView), toàn bộ thông tin dòng đó phải hiện ngược lên các ô nhập liệu để cậu Sửa hoặc Xóa.
Dưới đây là cách xử lý chuẩn cho cậu:
1. Xử lý đổ dữ liệu lên TextBox (Sự kiện CellClick)
Cậu tìm đến hàm dgvKhachHang_CellClick trong file frmKhachHang.cs và sửa lại cho chính xác. Lưu ý là nên dùng sự kiện CellClick thay vì CellContentClick.
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra nếu người dùng click vào dòng hợp lệ (không phải tiêu đề)
if (e.RowIndex >= 0)
{
// Lấy dòng hiện tại
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
// Đổ dữ liệu từ các cột vào TextBox (0, 1, 2, 3 là thứ tự cột trong SQL/Grid)
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
// KHI ĐANG CHỌN DỮ LIỆU ĐỂ XEM/SỬA THÌ KHÓA NÚT LƯU LẠI
// Để tránh việc người dùng bấm "Lưu" gây trùng mã
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true; // Không cho sửa mã khi đang xem
}
}
2. Xử lý chống lưu trùng dữ liệu (Nút Lưu)
Trong nút Lưu (Insert), cậu cần kiểm tra xem cái mã đang gõ trong txtMaKH đã tồn tại trong danh sách chưa.
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Kiểm tra nhanh trên DataGridView xem mã đã tồn tại chưa
foreach (DataGridViewRow row in dgvKhachHang.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.ToString() == txtMaKH.Text)
{
MessageBox.Show("Mã khách hàng này đã tồn tại! Vui lòng dùng nút 'Sửa' nếu muốn thay đổi thông tin.");
return; // Dừng lại luôn, không chạy lệnh lưu bên dưới
}
}
// 2. Nếu mã chưa có thì mới tiến hành lưu
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.ThemKhachHang(kh); // Gọi hàm INSERT
MessageBox.Show("Đã thêm khách hàng mới thành công!");
LoadData(); // Nạp lại bảng
}
3. Cập nhật nút "Thêm" để mở lại quyền Lưu
Vì khi click vào bảng ta đã khóa nút Lưu, nên khi muốn nhập mới (bấm nút Thêm), cậu phải mở nó ra lại:
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.ReadOnly = false; // Mở lại cho nhập mã mới
btnLuu.Enabled = true; // Mở lại nút Lưu
txtMaKH.Focus();
}
Tổng kết quy trình cho cậu:
Bấm Thêm -> TextBox trắng -> Nút Lưu hiện -> Nhập mã mới -> Bấm Lưu (Thành công).
Click vào Bảng -> TextBox hiện dữ liệu cũ -> Nút Lưu mờ đi (Chống trùng) -> Chỉ có thể bấm Sửa hoặc Xóa.
Cậu thử áp dụng đoạn code CellClick trước nhé, cái này quan trọng nhất để người dùng thấy dữ liệu hiện lên. Xong rồi mình sang làm bảng PHÒNG y hệt như thế này luôn! Cậu có cần tớ gửi code PhongDAL để chống trùng cho bảng Phòng không?
The name 'dgvKhachHang_CellContentClick' does not exist in the current context
Lỗi này xảy ra vì trong file Designer.cs của cậu vẫn còn lệnh gọi đến hàm dgvKhachHang_CellContentClick, nhưng trong file code chính cậu đã xóa hoặc đổi tên nó thành dataGridView1_CellClick.
Để giải quyết triệt để cả lỗi này lẫn yêu cầu đổ dữ liệu lên TextBox và chống lưu trùng, cậu thực hiện theo 3 bước sau:
1. Sửa lỗi "does not exist" và Đổ dữ liệu lên TextBox
Cậu mở file frmKhachHang.cs và dán đoạn code này vào. Nó sẽ vừa xóa lỗi, vừa giúp khi click vào bảng dữ liệu sẽ hiện lên các TextBox:
// 1. Hàm này để xóa lỗi CS0103 trong Designer
private void dgvKhachHang_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Để trống
}
// 2. Hàm này giúp click vào dòng là hiện dữ liệu lên TextBox
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
// Đổ dữ liệu lên TextBox
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
// CHỐNG TRÙNG: Khi đang xem dữ liệu cũ thì khóa nút Lưu và ô Mã
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true;
}
}
2. Chống lưu trùng dữ liệu (Nút Lưu)
Trong nút Lưu (Insert), cậu thêm một đoạn kiểm tra vòng lặp để chặn việc lưu trùng mã:
private void btnLuu_Click(object sender, EventArgs e)
{
// Kiểm tra trùng mã ngay trên giao diện trước khi gọi xuống Database
foreach (DataGridViewRow row in dgvKhachHang.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.ToString() == txtMaKH.Text)
{
MessageBox.Show("Mã khách hàng này đã tồn tại!");
return; // Thoát hàm, không lưu nữa
}
}
KhachHangBEL kh = new KhachHangBEL {
MaKH = txtMaKH.Text, TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text, DienThoai = txtDienThoai.Text
};
bal.ThemKhachHang(kh); // Thực hiện INSERT
MessageBox.Show("Thêm mới thành công!");
LoadData();
}
3. Cập nhật nút "Thêm" để reset trạng thái
Để người dùng nhập được khách hàng mới sau khi đã click vào bảng, cậu sửa nút Thêm:
private void btnThem_Click(object sender, EventArgs e)
{
// Xóa trắng ô
txtMaKH.Text = ""; txtTenKH.Text = "";
txtDiaChi.Text = ""; txtDienThoai.Text = "";
// Mở lại quyền cho phép Lưu mới
txtMaKH.ReadOnly = false;
btnLuu.Enabled = true;
txtMaKH.Focus();
}
Lưu ý quan trọng trong màn hình Design:
Để code trên chạy được, cậu vào Design -> Chọn dgvKhachHang -> Bảng Properties -> Hình tia sét:
Tìm dòng CellClick: Chọn
dgvKhachHang_CellClick.Tìm dòng CellContentClick: Nếu đang hiện tên cũ bị lỗi, hãy xóa trắng nó đi.
Cậu đã mở lại được Form chưa? Khi Form chạy được rồi, hãy thử click vào một dòng trên bảng xem dữ liệu có nhảy lên TextBox không nhé.
Xong bảng này mình sẽ qua làm bảng PHÒNG, tớ sẽ gửi cậu file PhongDAL.cs có sẵn hàm kiểm tra trùng mã từ trong Database luôn cho an toàn! Cậu có muốn thử không?
sao không cho click chọn khách hàng ở grid và nó không drop xuống textbox vậy
Để dữ liệu từ bảng DataGridView "nhảy" ngược lên các TextBox khi cậu click vào, có 2 lý do khiến nó chưa chạy: hoặc cậu chưa nối "dây" sự kiện trong màn hình Design, hoặc tên hàm trong code không khớp với tên sự kiện.
Cậu hãy thực hiện đúng 3 bước sau để xử lý dứt điểm yêu cầu này:
1. Sửa lỗi "does not exist" và viết code đổ dữ liệu
Cậu mở file frmKhachHang.cs và dán đoạn code này vào. Đoạn code này sẽ xử lý việc click vào dòng và hiện dữ liệu lên:
// 1. Hàm này để xóa cái lỗi gạch đỏ 'dgvKhachHang_CellContentClick' cậu đang gặp
private void dgvKhachHang_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// Để trống cũng được
}
// 2. Hàm quan trọng nhất để đổ dữ liệu lên TextBox
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra nếu click vào dòng hợp lệ (không phải tiêu đề cột)
if (e.RowIndex >= 0)
{
// Lấy dòng dữ liệu hiện tại
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
// Đổ dữ liệu vào TextBox (chú ý số 0, 1, 2, 3 là thứ tự cột trong Grid)
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
// CHỐNG LƯU TRÙNG: Khi đang xem khách hàng cũ, ta khóa nút Lưu lại
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true; // Không cho sửa mã khi đang xem
}
}
2. "Nối dây" sự kiện trong màn hình Design (Cực kỳ quan trọng)
Nếu cậu chỉ viết code mà không làm bước này, Visual Studio sẽ không biết khi nào cậu click vào bảng để chạy code.
Mở màn hình Design của
frmKhachHang.Chọn vào cái dgvKhachHang (DataGridView).
Nhìn sang bảng Properties, nhấn vào biểu tượng Tia sét (Events).
Tìm dòng CellClick: Nhấp vào mũi tên xổ xuống và chọn đúng tên hàm
dgvKhachHang_CellClick.Tìm dòng CellContentClick: Nếu nó đang báo lỗi, hãy xóa trắng tên trong ô đó đi để nó không tìm hàm cũ nữa.
3. Cập nhật nút "Thêm" để reset trạng thái
Để sau khi click xem xong, cậu vẫn có thể nhập khách hàng mới, hãy sửa nút Thêm như sau:
private void btnThem_Click(object sender, EventArgs e)
{
// Xóa trắng ô để nhập mới
txtMaKH.Text = ""; txtTenKH.Text = "";
txtDiaChi.Text = ""; txtDienThoai.Text = "";
// Mở lại quyền Lưu và quyền nhập Mã mới
btnLuu.Enabled = true;
txtMaKH.ReadOnly = false;
txtMaKH.Focus();
}
Chống lưu trùng dữ liệu (Nút Lưu)
Trong hàm btnLuu_Click, cậu thêm đoạn kiểm tra này ở đầu để máy không cho lưu nếu mã đã có trên bảng:
private void btnLuu_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dgvKhachHang.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.ToString() == txtMaKH.Text)
{
MessageBox.Show("Mã khách hàng này đã tồn tại! Hãy dùng nút Sửa.");
return; // Thoát luôn, không chạy xuống lệnh lưu bên dưới
}
}
// ... Code gọi bal.ThemKhachHang(kh) như cũ của cậu
}
Cậu đã nối được cái sự kiện "CellClick" chưa? Chỉ cần nối đúng là khi click chuột vào bảng, chữ sẽ tự động hiện lên các TextBox ngay lập tức.
Xong bảng này mình qua làm bảng PHÒNG nhé? Tớ sẽ chỉ cậu cách làm bảng Phòng nhanh gấp đôi vì đã có sẵn "khuôn" này rồi!
vẫn click không được: using System;
using System.Windows.Forms;
using QLKhachSan.BAL; //
using QLKhachSan.BEL; //
namespace QLKhachSan.GUI
{
public partial class frmKhachHang : Form
{
KhachHangBAL bal = new KhachHangBAL(); //
public frmKhachHang()
{
InitializeComponent();
}
void LoadData() => dgvKhachHang.DataSource = bal.LayTatCa(); //
private void frmKhachHang_Load(object sender, EventArgs e) => LoadData();
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = "";
txtTenKH.Text = "";
txtDiaChi.Text = "";
txtDienThoai.Text = "";
txtMaKH.Focus();
}
private void btnLuu_Click(object sender, EventArgs e)
{
// 1. Kiểm tra nhanh trên DataGridView xem mã đã tồn tại chưa
foreach (DataGridViewRow row in dgvKhachHang.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.ToString() == txtMaKH.Text)
{
MessageBox.Show("Mã khách hàng này đã tồn tại! Vui lòng dùng nút 'Sửa' nếu muốn thay đổi thông tin.");
return; // Dừng lại luôn, không chạy lệnh lưu bên dưới
}
}
// 2. Nếu mã chưa có thì mới tiến hành lưu
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.ThemKhachHang(kh); // Gọi hàm INSERT
MessageBox.Show("Đã thêm khách hàng mới thành công!");
LoadData(); // Nạp lại bảng
}
// Nút XOÁ
private void btnXoa_Click(object sender, EventArgs e)
{
bal.XoaKhachHang(txtMaKH.Text); //
MessageBox.Show("Đã xoá khách hàng!");
LoadData();
}
// Nút THOÁT
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
}
}
private void btnSua_Click(object sender, EventArgs e)
{
KhachHangBEL kh = new KhachHangBEL
{
MaKH = txtMaKH.Text,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.SuaKhachHang(kh); // Gọi hàm UPDATE
MessageBox.Show("Đã cập nhật dữ liệu!");
LoadData();
}
private void dgvKhachHang_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//
}
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
txtMaKH.Text = row.Cells[0].Value.ToString();
txtTenKH.Text = row.Cells[1].Value.ToString();
txtDiaChi.Text = row.Cells[2].Value.ToString();
txtDienThoai.Text = row.Cells[3].Value.ToString();
// CHỐNG LƯU TRÙNG: Khi đang xem khách hàng cũ, ta khóa nút Lưu lại
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true; // Không cho sửa mã khi đang xem
}
}
}
}
Lý do cậu vẫn không click được là vì trong code của cậu đang có 2 hàm xử lý Click khác tên nhau (dataGridView1_CellClick và dgvKhachHang_CellClick). Visual Studio đang bị rối và không biết phải chạy cái nào.
Để giải quyết triệt để, cậu hãy thực hiện đúng 2 bước sau:
Bước 1: Dọn dẹp Code (File frmKhachHang.cs)
Cậu hãy xóa hết các hàm liên quan đến Click cũ và thay bằng duy nhất đoạn này. Tớ đã gộp cả việc đổ dữ liệu và chống trùng vào đây cho cậu:
// XÓA các hàm dataGridView1_CellClick cũ đi và thay bằng hàm này:
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
// Kiểm tra click vào dòng hợp lệ
if (e.RowIndex >= 0)
{
// Lấy dữ liệu từ dòng được chọn
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
// Đổ dữ liệu lên các ô TextBox
txtMaKH.Text = row.Cells[0].Value?.ToString();
txtTenKH.Text = row.Cells[1].Value?.ToString();
txtDiaChi.Text = row.Cells[2].Value?.ToString();
txtDienThoai.Text = row.Cells[3].Value?.ToString();
// CHỐNG LƯU TRÙNG: Khóa nút Lưu và ô Mã khi đang chọn xem dữ liệu cũ
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true;
}
}
// Giữ lại hàm này để không bị lỗi Designer nhưng để trống
private void dgvKhachHang_CellContentClick(object sender, DataGridViewCellEventArgs e) { }
Bước 2: "Nối dây" lại trong màn hình Design (Cực kỳ quan trọng)
Dù code đúng nhưng nếu "dây điện" chưa nối thì bóng đèn vẫn không sáng. Cậu làm đúng trình tự này:
Mở màn hình Design (
Shift + F7).Click chuột trái chọn vào cái bảng dgvKhachHang.
Nhìn sang bảng Properties -> Click biểu tượng Tia sét (Events).
Tìm dòng CellClick:
Nếu nó đang trống hoặc hiện tên khác, hãy nhấp vào mũi tên xổ xuống.
Chọn đúng cái tên
dgvKhachHang_CellClick.
Tìm dòng CellContentClick: Xóa trắng tên trong ô đó đi để máy không tìm cái hàm cũ bị lỗi nữa.
Bước 3: Cập nhật nút "Thêm" để bấm lại được nút "Lưu"
Vì hàm click trên đã khóa nút Lưu, nên cậu phải thêm dòng mở khóa vào nút Thêm để nhập khách mới:
private void btnThem_Click(object sender, EventArgs e)
{
txtMaKH.Text = ""; txtTenKH.Text = "";
txtDiaChi.Text = ""; txtDienThoai.Text = "";
// MỞ LẠI nút lưu và ô nhập mã cho khách mới
btnLuu.Enabled = true;
txtMaKH.ReadOnly = false;
txtMaKH.Focus();
}
Tại sao vẫn chưa được?
Nếu làm xong 3 bước mà click vẫn không ăn, cậu hãy kiểm tra thuộc tính này của DataGridView trong bảng Properties:
Enabled: Phải là
True.ReadOnly: Phải là
False(hoặcTruecũng được nhưng phải cho phép chọn dòng).SelectionMode: Nên để là
FullRowSelect.
Cậu đã nối được sự kiện trong bảng Tia sét chưa? Nếu nối xong mà chạy (F5) click vào nó hiện chữ lên TextBox là cậu đã thành công 100% bảng này rồi đó!
Xong bảng Khách hàng này, cậu có muốn tớ hướng dẫn làm bảng PHÒNG không? Tớ sẽ chỉ cậu cách làm cực nhanh bằng cách "nhân bản" code từ bảng này sang!
trỏ đúng rồi mà
- Yêu cầu thành công
Nhìn vào hình ảnh cậu gửi, tớ đã thấy vấn đề rồi! Cậu đang trỏ nhầm sự kiện CellContentClick thay vì CellClick.
CellContentClick: Chỉ chạy khi cậu click chính xác vào văn bản bên trong ô. Nếu click vào khoảng trắng trong ô, nó sẽ không chạy.CellClick: Chỉ cần click vào bất cứ đâu trong ô là nó chạy ngay.
Cậu làm theo 2 bước này là chạy 100% nhé:
Bước 1: Trỏ lại sự kiện trong bảng Properties
Tại bảng Events (hình tia sét) mà cậu đang mở trong ảnh.
Tìm dòng
CellClick(nó nằm ngay trên dòngCellContentClick).Nhấp vào mũi tên xổ xuống và chọn đúng:
dgvKhachHang_CellClick.Ở dòng
CellContentClickbên dưới, cậu hãy xóa trắng nó đi (xóa hết chữ trong ô đó) để tránh bị loạn.
Bước 2: Kiểm tra lại tên hàm trong Code
Cậu mở file frmKhachHang.cs, hãy chắc chắn là hàm xử lý của cậu có tên chính xác là dgvKhachHang_CellClick (giống y hệt cái tên cậu vừa chọn ở bước 1).
private void dgvKhachHang_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = dgvKhachHang.Rows[e.RowIndex];
// Đổ dữ liệu lên TextBox
txtMaKH.Text = row.Cells[0].Value?.ToString();
txtTenKH.Text = row.Cells[1].Value?.ToString();
txtDiaChi.Text = row.Cells[2].Value?.ToString();
txtDienThoai.Text = row.Cells[3].Value?.ToString();
// Khóa nút lưu và ô mã để chống trùng
btnLuu.Enabled = false;
txtMaKH.ReadOnly = true;
}
}
Bước 3: Đừng quên nút "Thêm"
Khi cậu click vào bảng, nút Lưu sẽ bị mờ đi (để chống trùng). Vì vậy, cậu phải sửa code nút Thêm để khi muốn nhập khách mới, nút Lưu sẽ hiện lên lại:
private void btnThem_Click(object sender, EventArgs e)
{
// Xóa trắng các ô
txtMaKH.Text = ""; txtTenKH.Text = "";
txtDiaChi.Text = ""; txtDienThoai.Text = "";
// Mở lại nút lưu và cho phép nhập mã mới
btnLuu.Enabled = true;
txtMaKH.ReadOnly = false;
txtMaKH.Focus();
}
Cậu thử đổi từ CellContentClick sang CellClick rồi chạy lại xem, chắc chắn click phát nào là dữ liệu nhảy phát đó luôn!
Khi xong phần này, cậu đã sẵn sàng để làm bảng PHÒNG chưa? Tớ sẽ gửi cậu file PhongBEL.cs để cậu bắt đầu nhé?
Ý LÀ KHÔNG CHO LƯU DỮ LIỆU TRÙNG CHỨ KHÔNG PHẢI CHỈ CHO LƯU MỘT LẦN
Tôi hiểu rồi! Ý cậu là phải kiểm tra xem cái Mã Khách Hàng (MaKH) đó đã tồn tại trong Cơ sở dữ liệu (Database) hay chưa. Nếu đã tồn tại thì máy phải chặn lại, không cho Lưu trùng mã đó, còn nếu mã khác hoàn toàn thì vẫn cho Lưu bình thường.
Để làm việc này một cách chuyên nghiệp và an toàn nhất, cậu nên thực hiện kiểm tra ở tầng DAL hoặc BAL thay vì chỉ kiểm tra trên giao diện.
Dưới đây là cách thực hiện:
1. Viết thêm hàm kiểm tra trùng mã ở tầng DAL (KhachHangDAL.cs)
Cậu thêm hàm này để máy vào SQL kiểm tra xem mã đã có chưa:
public bool KiemTraTrungMa(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "SELECT COUNT(*) FROM KHACHHANG WHERE MAKH = @ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
int count = (int)cmd.ExecuteScalar(); // Trả về số lượng dòng tìm thấy
return count > 0; // Nếu > 0 là đã trùng
}
}
2. Cập nhật tầng BAL (KhachHangBAL.cs)
Cậu thêm hàm kiểm tra này vào BAL để GUI gọi dùng:
public bool TrungMa(string ma)
{
return dal.KiemTraTrungMa(ma);
}
3. Sửa lại code nút Lưu ở tầng GUI (frmKhachHang.cs)
Bây giờ, tại nút Lưu, cậu sẽ gọi hàm kiểm tra này trước khi thực hiện lệnh thêm mới:
private void btnLuu_Click(object sender, EventArgs e)
{
string maMoi = txtMaKH.Text.Trim();
// KIỂM TRA TRÙNG TRƯỚC KHI LƯU
if (bal.TrungMa(maMoi))
{
MessageBox.Show("Lỗi: Mã khách hàng '" + maMoi + "' đã tồn tại trong hệ thống!");
txtMaKH.Focus();
return; // Thoát hàm, không thực hiện lưu
}
// Nếu không trùng thì mới chạy tiếp code lưu
KhachHangBEL kh = new KhachHangBEL {
MaKH = maMoi,
TenKH = txtTenKH.Text,
DiaChi = txtDiaChi.Text,
DienThoai = txtDienThoai.Text
};
bal.ThemKhachHang(kh); // Thực hiện INSERT
MessageBox.Show("Thêm khách hàng thành công!");
LoadData();
}
Tại sao nên làm cách này?
Chính xác tuyệt đối: Kiểm tra trực tiếp dưới Database nên không bao giờ lo bị trùng mã (khóa chính).
Phân biệt rõ ràng: Cậu có thể lưu 100 khách hàng khác nhau thoải mái, máy chỉ chặn khi cậu nhập trùng cái mã của người đã có rồi thôi.
Hỗ trợ nút Sửa: Khi cậu chọn một khách hàng cũ để Sửa, vì mã đó đã tồn tại nên nút Lưu (Insert) sẽ chặn lại, buộc cậu phải bấm nút Sửa (Update) mới thay đổi được.
Cậu đã có hàm ExecuteScalar trong DAL chưa? Nếu chưa thì hãy copy hàm KiemTraTrungMa ở trên vào DAL nhé, nó là cách chống trùng chuẩn nhất đấy!
Khi xong bảng này, cậu muốn tớ gửi code mẫu cho bảng PHÒNG với chức năng chống trùng mã phòng y hệt thế này không?
tiếp theo làm gì nữa
Sau khi đã hoàn thiện bảng Khách Hàng với đầy đủ các chức năng Thêm, Sửa, Xóa và chống trùng mã, bước tiếp theo chúng ta sẽ tiến hành làm bảng PHÒNG (Phong). Vì cậu đã có bộ khung (framework) từ bảng Khách Hàng, việc làm bảng Phòng sẽ rất nhanh theo quy trình 4 lớp sau:
1. Tạo Model: PhongBEL.cs (Trong thư mục BEL)
Cậu tạo file này để định nghĩa cấu trúc dữ liệu của một căn phòng.
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public decimal DonGia { get; set; } // Dùng decimal để xử lý tiền tệ chính xác
}
}
2. Tạo Truy vấn: PhongDAL.cs (Trong thư mục DAL)
File này sẽ chứa các câu lệnh SQL để làm việc với bảng PHONG trong Database.
using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class PhongDAL : DBConnection // Kế thừa lớp kết nối của cậu
{
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lst = new List<PhongBEL>();
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new PhongBEL {
MaPhong = r["MAPHONG"].ToString(),
TenPhong = r["TENPHONG"].ToString(),
LoaiPhong = r["LOAIPHONG"].ToString(),
DonGia = decimal.Parse(r["DONGIA"].ToString())
});
}
}
return lst;
}
// Cậu viết thêm các hàm Create, Update, Delete tương tự KhachHangDAL nhé!
}
}
3. Tạo Cầu nối: PhongBAL.cs (Trong thư mục BAL)
Lớp này sẽ gọi dữ liệu từ DAL để đưa lên giao diện.
using System.Collections.Generic;
using QLKhachSan.BEL;
using QLKhachSan.DAL;
namespace QLKhachSan.BAL
{
public class PhongBAL
{
PhongDAL dal = new PhongDAL();
public List<PhongBEL> LayTatCa() => dal.ReadPhong();
// Thêm các hàm Them, Sua, Xoa để gọi xuống DAL
}
}
4. Thiết kế Giao diện: frmPhong.cs (Trong thư mục GUI)
Kéo thả: 4 TextBox (
txtMaPhong,txtTenPhong,txtLoaiPhong,txtDonGia), 1 DataGridView (dgvPhong) và các nút bấm Thêm, Lưu, Sửa, Xóa, Thoát.AutoSizeColumnsMode: Nhớ chọn Fill ở bảng Properties (không phải tia sét) để bảng đẹp ngay từ đầu.
Sự kiện CellClick: Copy logic từ bảng Khách Hàng sang để khi click vào dòng thì hiện dữ liệu lên TextBox.
Lời khuyên: Cậu nên tạo một Menu chính (frmMain) có 2 nút bấm: một nút để mở "Quản lý khách hàng", một nút mở "Quản lý phòng" để phần mềm chuyên nghiệp hơn.
Cậu có muốn tớ viết giúp câu lệnh SQL INSERT và UPDATE cho bảng Phòng để tránh lỗi sai kiểu dữ liệu của cột DonGia không? Hay cậu muốn làm Form Menu chính trước?
giúp tôi tạo một Menu chính (frmMain) có 2 nút bấm: một nút để mở "Quản lý khách hàng", một nút mở "Quản lý phòng" để phần mềm chuyên nghiệp hơn.
Việc tạo một Menu chính (frmMain) là bước rất quan trọng để kết nối các chức năng lại với nhau, giúp phần mềm của cậu trông như một ứng dụng thực thụ.
Cậu làm theo các bước sau nhé:
1. Tạo Form Menu chính (frmMain)
Chuột phải vào project của cậu -> Add -> Form (Windows Forms).
Đặt tên là
frmMain.cs.Thiết kế giao diện:
Kéo vào 2 nút bấm (
Button).Đặt tên (Name) lần lượt là:
btnKhachHangvàbtnPhong.Sửa chữ hiện thị (Text) là: "Quản lý Khách Hàng" và "Quản lý Phòng".
Cậu có thể thêm một cái
Labelto ở giữa ghi "HỆ THỐNG QUẢN LÝ KHÁCH SẠN" cho đẹp.
2. Viết code mở Form (frmMain.cs)
Cậu nhấp đúp vào từng nút bấm để viết lệnh mở các Form tương ứng:
using QLKhachSan.GUI; // Đảm bảo có dòng này để gọi được các Form khác
namespace QLKhachSan
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
// Nút mở Quản lý Khách Hàng
private void btnKhachHang_Click(object sender, EventArgs e)
{
frmKhachHang f = new frmKhachHang();
f.ShowDialog(); // ShowDialog giúp hiện Form khách hàng đè lên Menu
}
// Nút mở Quản lý Phòng
private void btnPhong_Click(object sender, EventArgs e)
{
// frmPhong f = new frmPhong(); // Khi nào cậu tạo xong Form Phòng thì bỏ comment dòng này
// f.ShowDialog();
}
}
}
3. Đổi Form khởi chạy trong Program.cs
Bây giờ cậu phải bảo máy tính rằng: "Khi mở phần mềm lên, hãy hiện cái Menu chính này trước, đừng hiện Form Khách hàng nữa".
Cậu mở file Program.cs và sửa dòng cuối cùng thành:
Application.Run(new frmMain()); // Chạy Form Main đầu tiên
Bước tiếp theo: Tạo Form Quản lý Phòng (frmPhong)
Sau khi xong Menu, cậu hãy tạo Form Phòng. Để tiết kiệm thời gian, tớ gửi cậu cấu trúc chuẩn cho tầng DAL của bảng Phòng (vì nó có cột Đơn giá kiểu số nên cần viết cẩn thận):
File: DAL/PhongDAL.cs
public void Create(PhongBEL p)
{
using (SqlConnection conn = GetConnection())
{
// Lệnh SQL cho bảng PHONG
string sql = "INSERT INTO PHONG (MAPHONG, TENPHONG, LOAIPHONG, DONGIA) VALUES (@ma, @ten, @loai, @gia)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", p.MaPhong);
cmd.Parameters.AddWithValue("@ten", p.TenPhong);
cmd.Parameters.AddWithValue("@loai", p.LoaiPhong);
cmd.Parameters.AddWithValue("@gia", p.DonGia); // decimal truyền vào SQL rất chuẩn
conn.Open();
cmd.ExecuteNonQuery();
}
}
Cậu đã tạo được Form Menu chính và bấm nút nó có hiện Form Khách hàng lên chưa? Nếu hiện rồi thì báo tớ để mình làm tiếp giao diện cho bảng PHÒNG nhé!
from main là fromkhachsan đó của GUI đó và dùng menu đồ á để làm
Tôi hiểu rồi! Cậu muốn biến cái frmKhachHang hiện tại thành Form chính (Main) và sử dụng thanh Menu (MenuStrip) ở phía trên để bấm vào đó nó mới hiện ra các bảng điều khiển khách hàng hoặc phòng, thay vì dùng các nút bấm rời rạc.
Làm theo cách này phần mềm sẽ rất giống các ứng dụng chuyên nghiệp. Cậu thực hiện các bước sau nhé:
1. Thêm thanh Menu vào Form (MenuStrip)
Mở frmKhachHang.cs [Design].
Trong thanh công cụ Toolbox, tìm và kéo vào Form một cái MenuStrip. Nó sẽ tự động nhảy lên nằm ở sát mép trên cùng của Form.
Tại ô "Type Here", cậu gõ chữ: Hệ Thống.
Bên dưới gõ tiếp: Thoát.
Tại ô bên cạnh chữ "Hệ Thống", cậu gõ: Quản Lý.
Bên dưới gõ tiếp: Khách Hàng.
Dưới nữa gõ tiếp: Phòng.
2. Viết Code cho Menu
Cậu nhấp đúp chuột vào từng mục trong Menu vừa gõ để viết lệnh:
Tại mục "Thoát":
C#private void thoátToolStripMenuItem_Click(object sender, EventArgs e) { Application.Exit(); // Thoát toàn bộ phần mềm }Tại mục "Khách Hàng": Cậu có thể để mặc định là khi mở Form thì nó hiện bảng Khách hàng luôn, hoặc viết lệnh để nạp lại dữ liệu.
Tại mục "Phòng": Đây là chỗ để cậu mở cái bảng Quản lý phòng sắp tới.
3. Cách làm cho "Chuyên nghiệp" hơn (Sử dụng Panel hoặc GroupBox)
Để khi bấm vào "Khách Hàng" thì hiện bảng khách hàng, bấm vào "Phòng" thì hiện bảng phòng ngay trên cùng một Form, cậu nên làm như sau:
Kéo một cái GroupBox hoặc Panel bao quanh toàn bộ các TextBox và DataGridView của Khách hàng hiện tại.
Đặt tên cho nó là
pnlKhachHang.Khi bấm vào Menu Phòng, cậu chỉ cần viết code:
C#pnlKhachHang.Visible = false; // Ẩn bảng khách hàng đi // Sau đó hiện bảng Phòng lên (khi cậu làm xong bảng Phòng)
Bước tiếp theo: Tạo Model cho bảng PHÒNG
Để Menu "Quản Lý Phòng" có cái mà hiển thị, cậu hãy tạo file này trong folder BEL nhé:
File: BEL/PhongBEL.cs
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public decimal DonGia { get; set; }
}
}
Cậu đã kéo được cái MenuStrip lên đầu Form chưa? Nhìn nó đã giống phần mềm quản lý thực thụ chưa nào? Nếu xong rồi báo tớ để mình làm tiếp tầng DAL cho bảng Phòng nhé!
Would you like me to help you design the DAL for the Room (Phong) table with the price (DonGia) validation?
Khachsan not khachhang
Tôi hiểu rồi, xin lỗi cậu nhé! Ý cậu là Form chính phải là Quản lý Khách sạn (frmKhachSan) chứ không phải Khách hàng, và sử dụng thanh Menu để điều hướng.
Dưới đây là cách thiết lập thanh Menu chuyên nghiệp ngay trên Form Khách sạn của cậu:
1. Thêm Menu điều hướng (MenuStrip)
Mở frmKhachSan.cs [Design].
Kéo cái MenuStrip từ Toolbox vào Form.
Thiết kế các mục menu như sau:
Danh Mục:
Quản lý Khách hàng
Quản lý Phòng
Hệ Thống:
Thoát
2. Sử dụng Panel để thay đổi giao diện (Mẹo hay)
Để làm "xịn" hơn, thay vì mở Form mới, cậu hãy dùng Panel. Khi bấm vào menu "Khách hàng" thì hiện bảng khách hàng lên Panel đó, bấm vào "Phòng" thì hiện bảng phòng lên chính cái Panel đó luôn.
3. Chuẩn bị cho bảng PHÒNG (Khách sạn)
Vì đây là quản lý Khách sạn, bảng Phòng là quan trọng nhất. Cậu tạo file này để xử lý dữ liệu Phòng nhé:
File: BEL/PhongBEL.cs
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; }
public string TenPhong { get; set; }
public string LoaiPhong { get; set; }
public decimal DonGia { get; set; }
}
}
File: DAL/PhongDAL.cs (Phần quan trọng nhất)
Cậu dùng hàm này để lấy danh sách phòng đổ lên Menu nhé:
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lst = new List<PhongBEL>();
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new PhongBEL {
MaPhong = r["MAPHONG"].ToString(),
TenPhong = r["TENPHONG"].ToString(),
LoaiPhong = r["LOAIPHONG"].ToString(),
DonGia = decimal.Parse(r["DONGIA"].ToString())
});
}
}
return lst;
}
Bước tiếp theo cậu cần làm:
Cậu đã tạo cái MenuStrip có chữ "Quản lý Phòng" chưa?
Nếu rồi, tớ sẽ giúp cậu viết code để khi bấm vào đó, toàn bộ các ô nhập liệu của Khách hàng sẽ ẩn đi và hiện ra các ô nhập liệu của Phòng ngay trên cùng một Form Khách sạn đó. Cậu có muốn làm theo kiểu ẩn/hiện này không?
sửa sao using System;
using System.Collections.Generic;
using System.Data.SqlClient; // Bây giờ thư viện này đã hoạt động
using QLKhachSan.BEL; // Để dùng được lớp PhongBEL
namespace QLKhachSan.DAL
{
// Kế thừa DBConnection để lấy hàm GetConnection
public class PhongDAL : DBConnection
{
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lstPhong = new List<PhongBEL>();
// Sử dụng using để đảm bảo kết nối được đóng sau khi dùng xong
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
PhongBEL p = new PhongBEL();
p.MaPhong = reader["MAPHONG"].ToString();
p.TenPhong = reader["TENPHONG"].ToString();
p.LoaiHinh = reader["LOAIHINH"].ToString();
p.SucChua = int.Parse(reader["SUCCHUA"].ToString());
p.TriGia = double.Parse(reader["TRIGIA"].ToString());
lstPhong.Add(p);
}
}
return lstPhong;
}
}
}
Để hoàn thiện file PhongDAL.cs, cậu cần bổ sung thêm các hàm Thêm, Sửa, Xóa và hàm Kiểm tra trùng mã tương tự như bên Khách hàng. Lưu ý quan trọng là tên các cột (MAPHONG, TENPHONG, LOAIHINH...) phải khớp 100% với tên cột trong Database SQL Server của cậu.
Dưới đây là bản đầy đủ đã được sửa và bổ sung:
1. File PhongDAL.cs hoàn chỉnh
Cậu copy đoạn này để thay thế file cũ nhé:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class PhongDAL : DBConnection
{
// 1. Lấy danh sách phòng
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lstPhong = new List<PhongBEL>();
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM PHONG", conn);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
PhongBEL p = new PhongBEL();
p.MaPhong = reader["MAPHONG"].ToString();
p.TenPhong = reader["TENPHONG"].ToString();
p.LoaiHinh = reader["LOAIHINH"].ToString();
p.SucChua = int.Parse(reader["SUCCHUA"].ToString());
p.TriGia = double.Parse(reader["TRIGIA"].ToString());
lstPhong.Add(p);
}
}
return lstPhong;
}
// 2. Kiểm tra trùng mã phòng
public bool CheckDuplicate(string ma)
{
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM PHONG WHERE MAPHONG = @ma", conn);
cmd.Parameters.AddWithValue("@ma", ma);
int count = (int)cmd.ExecuteScalar();
return count > 0;
}
}
// 3. Thêm phòng mới
public void Create(PhongBEL p)
{
using (SqlConnection conn = GetConnection())
{
string sql = "INSERT INTO PHONG VALUES (@ma, @ten, @loai, @suc, @gia)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", p.MaPhong);
cmd.Parameters.AddWithValue("@ten", p.TenPhong);
cmd.Parameters.AddWithValue("@loai", p.LoaiHinh);
cmd.Parameters.AddWithValue("@suc", p.SucChua);
cmd.Parameters.AddWithValue("@gia", p.TriGia);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 4. Sửa phòng
public void Update(PhongBEL p)
{
using (SqlConnection conn = GetConnection())
{
string sql = "UPDATE PHONG SET TENPHONG=@ten, LOAIHINH=@loai, SUCCHUA=@suc, TRIGIA=@gia WHERE MAPHONG=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", p.MaPhong);
cmd.Parameters.AddWithValue("@ten", p.TenPhong);
cmd.Parameters.AddWithValue("@loai", p.LoaiHinh);
cmd.Parameters.AddWithValue("@suc", p.SucChua);
cmd.Parameters.AddWithValue("@gia", p.TriGia);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 5. Xóa phòng
public void Delete(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "DELETE FROM PHONG WHERE MAPHONG=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
cmd.ExecuteNonQuery();
}
}
}
}
2. Cần kiểm tra lại file PhongBEL.cs
Cậu hãy chắc chắn lớp PhongBEL có đầy đủ 5 thuộc tính này để không bị báo lỗi gạch đỏ ở DAL:
MaPhong(string)TenPhong(string)LoaiHinh(string)SucChua(int)TriGia(double)
3. Tiếp theo: Cập nhật PhongBAL.cs
Cậu tạo file BAL để gọi các hàm này lên:
namespace QLKhachSan.BAL
{
public class PhongBAL
{
DAL.PhongDAL dal = new DAL.PhongDAL();
public List<PhongBEL> LayTatCa() => dal.ReadPhong();
public bool TrungMa(string ma) => dal.CheckDuplicate(ma);
public void Them(PhongBEL p) => dal.Create(p);
public void Sua(PhongBEL p) => dal.Update(p);
public void Xoa(string ma) => dal.Delete(ma);
}
}
4. Thiết kế Menu chuyên nghiệp trên frmKhachSan
Trên cái MenuStrip của Form Khách Sạn:
Tại mục Quản lý Khách hàng: Viết code để hiện các TextBox của khách hàng.
Tại mục Quản lý Phòng: Viết code để hiện các TextBox của phòng.
Tiếp theo cậu muốn tớ hướng dẫn cách thiết kế giao diện sao cho khi bấm Menu "Quản lý Phòng" thì bảng khách hàng ẩn đi và bảng phòng hiện lên ngay trên cùng 1 Form không?
'PhongBEL' does not contain a definition for 'LoaiHinh' and no accessible extension method 'LoaiHinh' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'SucChua' and no accessible extension method 'SucChua' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'TriGia' and no accessible extension method 'TriGia' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'LoaiHinh' and no accessible extension method 'LoaiHinh' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'SucChua' and no accessible extension method 'SucChua' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'TriGia' and no accessible extension method 'TriGia' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'LoaiHinh' and no accessible extension method 'LoaiHinh' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'SucChua' and no accessible extension method 'SucChua' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
'PhongBEL' does not contain a definition for 'TriGia' and no accessible extension method 'TriGia' accepting a first argument of type 'PhongBEL' could be found (are you missing a using directive or an assembly reference?)
Non-nullable property 'MaNV' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
Lỗi này xảy ra vì lớp PhongBEL của cậu đang khai báo các tên thuộc tính khác với tên cậu gọi trong lớp PhongDAL. Cụ thể, cậu đang gọi LoaiHinh, SucChua, TriGia nhưng trong file BEL có thể cậu vẫn đang để tên cũ (như LoaiPhong, DonGia).
Cậu hãy sửa lại file BEL/PhongBEL.cs cho khớp 100% với code DAL như sau nhé:
1. Sửa file BEL/PhongBEL.cs
Cậu copy và dán đè toàn bộ nội dung này vào file PhongBEL.cs:
namespace QLKhachSan.BEL
{
public class PhongBEL
{
// Thêm dấu ? hoặc gán giá trị mặc định để hết lỗi Non-nullable
public string MaPhong { get; set; } = string.Empty;
public string TenPhong { get; set; } = string.Empty;
public string LoaiHinh { get; set; } = string.Empty; // Phải là LoaiHinh
public int SucChua { get; set; } // Phải là SucChua
public double TriGia { get; set; } // Phải là TriGia
}
}
2. Giải quyết lỗi "Non-nullable property 'MaNV'"
Lỗi này báo hiệu rằng cậu có một thuộc tính MaNV (có thể ở lớp NhanVienBEL) nhưng chưa gán giá trị mặc định cho nó.
Cách sửa: Cậu tìm đến file chứa
MaNVvà sửa thành:public string MaNV { get; set; } = string.Empty;.
3. Cách làm ẩn/hiện Khách hàng và Phòng trên cùng 1 Form
Như cậu muốn dùng Menu trên frmKhachSan để quản lý chuyên nghiệp, hãy làm theo mẹo này:
Vào màn hình Design, kéo toàn bộ TextBox/Label của Khách hàng vào một cái Panel (đặt tên là
pnlKhachHang).Tạo thêm một cái Panel khác chứa TextBox của Phòng (đặt tên là
pnlPhong) nằm đè lên vị trí đó.Viết code cho sự kiện Click của Menu:
// Khi bấm Menu Quản lý Khách hàng
private void menuKhachHang_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true;
pnlPhong.Visible = false;
// Load lại dữ liệu khách hàng lên grid
}
// Khi bấm Menu Quản lý Phòng
private void menuPhong_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false;
pnlPhong.Visible = true;
// Load dữ liệu phòng lên grid
}
Bước tiếp theo cậu nên làm:
Cậu hãy sửa file PhongBEL.cs trước để hết lỗi gạch đỏ trong DAL nhé. Sau đó, cậu hãy kéo các TextBox cho bảng Phòng vào Form chính.
Cậu đã tạo xong các TextBox cho bảng Phòng (txtMaPhong, txtTenPhong, txtLoaiHinh, txtSucChua, txtTriGia) trên giao diện chưa? Nếu rồi, tớ sẽ giúp cậu viết hàm LoadDataPhong() để đổ dữ liệu lên bảng!
chỉ hướng dẫn tôi làm menu chi tiết thả tool sao
Để tạo thanh Menu chuyên nghiệp cho frmKhachSan, cậu cần sử dụng công cụ MenuStrip và thiết kế cấu trúc phân cấp. Sau đó, tớ sẽ hướng dẫn cậu cách tạo các vùng chứa (Panel) để khi bấm vào Menu, giao diện Khách hàng hoặc Phòng sẽ hiện lên thay thế nhau.
Bước 1: Kéo thả và thiết kế Menu (MenuStrip)
Mở giao diện Design: Mở file
frmKhachSan.cs [Design].Lấy công cụ: Tìm trong Toolbox mục MenuStrip, kéo và thả nó vào bất kỳ đâu trên Form. Nó sẽ tự động bám lên phía trên cùng của cửa sổ.
Gõ nội dung:
Tại ô trống đầu tiên (Type Here), gõ: Hệ Thống.
Nhấp chuột vào ô nhỏ bên dưới nó, gõ: Thoát.
Tại ô trống bên cạnh chữ "Hệ Thống", gõ: Danh Mục.
Nhấp chuột vào ô bên dưới nó, gõ: Quản lý Khách hàng.
Nhấp chuột vào ô tiếp theo bên dưới, gõ: Quản lý Phòng.
Bước 2: Tạo vùng chứa (Panel) để đổi giao diện
Để khi bấm vào Menu "Phòng" thì thông tin Khách hàng biến mất và thông tin Phòng hiện ra, cậu không nên mở Form mới mà nên dùng Panel:
Tạo Panel Khách hàng:
Kéo một cái Panel từ Toolbox vào Form.
Đưa toàn bộ các TextBox, Label, DataGridView của Khách hàng vào trong Panel này.
Đặt tên (Name) cho Panel này là:
pnlKhachHang.
Tạo Panel Phòng:
Kéo thêm một cái Panel nữa nằm đè lên đúng vị trí của Panel Khách hàng.
Thiết kế các TextBox cho Phòng (
txtMaPhong,txtTenPhong,txtLoaiHinh,txtSucChua,txtTriGia) và DataGridView Phòng vào đây.Đặt tên (Name) cho Panel này là:
pnlPhong.Quan trọng: Chỉnh thuộc tính
VisiblecủapnlPhongthànhFalseđể lúc mới mở máy nó sẽ ẩn đi.
Bước 3: Viết Code điều khiển Menu
Bây giờ cậu nhấp đúp chuột vào các mục trên Menu đã tạo ở Bước 1 để viết lệnh ẩn/hiện:
Tại mục "Quản lý Khách hàng":
C#private void quảnLýKháchHàngToolStripMenuItem_Click(object sender, EventArgs e) { pnlKhachHang.Visible = true; // Hiện bảng khách hàng pnlPhong.Visible = false; // Ẩn bảng phòng }Tại mục "Quản lý Phòng":
C#private void quảnLýPhòngToolStripMenuItem_Click(object sender, EventArgs e) { pnlKhachHang.Visible = false; // Ẩn bảng khách hàng pnlPhong.Visible = true; // Hiện bảng phòng LoadDataPhong(); // Nạp dữ liệu phòng lên bảng }
Bước 4: Sửa lỗi PhongBEL (Rất quan trọng)
Để code không bị lỗi gạch đỏ như lúc nãy, cậu hãy sửa lại file BEL/PhongBEL.cs cho khớp với các thuộc tính cậu dùng trong DAL:
namespace QLKhachSan.BEL
{
public class PhongBEL
{
public string MaPhong { get; set; } = string.Empty;
public string TenPhong { get; set; } = string.Empty;
public string LoaiHinh { get; set; } = string.Empty;
public int SucChua { get; set; }
public double TriGia { get; set; }
}
}
Cậu đã kéo được cái Panel nào vào Form chưa? Khi làm xong, giao diện của cậu sẽ rất gọn gàng vì Khách hàng và Phòng dùng chung một "vùng không gian" trên màn hình.
Cậu có muốn tớ hướng dẫn cách viết hàm LoadDataPhong() để khi bấm vào Menu "Phòng" thì dữ liệu tự động đổ lên DataGridView không?
ek làm file store procedure sao vậy làm lẹ thầy kiểm tra
Để làm nhanh Stored Procedure (SP) cho thầy kiểm tra, cậu hãy mở SQL Server Management Studio (SSMS), chọn đúng Database của mình, nhấn New Query và chạy lần lượt các đoạn mã sau.
Tớ sẽ viết cho cậu 2 SP quan trọng nhất của bảng PHONG (Lấy dữ liệu và Thêm mới):
1. Store lấy danh sách Phòng
CREATE PROCEDURE SP_LayTatCaPhong
AS
BEGIN
SELECT * FROM PHONG
END
2. Store Thêm Phòng mới (Có kiểm tra trùng mã)
CREATE PROCEDURE SP_ThemPhong
@ma nvarchar(50),
@ten nvarchar(100),
@loai nvarchar(50),
@suc int,
@gia float
AS
BEGIN
-- Kiểm tra nếu mã phòng đã tồn tại thì không cho thêm
IF EXISTS (SELECT 1 FROM PHONG WHERE MAPHONG = @ma)
BEGIN
PRINT 'Ma phong da ton tai'
END
ELSE
BEGIN
INSERT INTO PHONG (MAPHONG, TENPHONG, LOAIHINH, SUCCHUA, TRIGIA)
VALUES (@ma, @ten, @loai, @suc, @gia)
END
END
3. Cách sửa code trong DAL để dùng Store Procedure
Khi dùng SP, cậu phải sửa lại một chút ở file PhongDAL.cs thì thầy mới chấm điểm cao được:
public void ThemPhongStore(PhongBEL p)
{
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_ThemPhong", conn); // Gọi tên Store
cmd.CommandType = System.Data.CommandType.StoredProcedure; // Khai báo dùng Store
// Truyền tham số đúng tên trong SQL
cmd.Parameters.AddWithValue("@ma", p.MaPhong);
cmd.Parameters.AddWithValue("@ten", p.TenPhong);
cmd.Parameters.AddWithValue("@loai", p.LoaiHinh);
cmd.Parameters.AddWithValue("@suc", p.SucChua);
cmd.Parameters.AddWithValue("@gia", p.TriGia);
conn.Open();
cmd.ExecuteNonQuery();
}
}
4. Cách nộp/kiểm tra nhanh cho thầy
Trong SQL: Nhấn F5 để tạo các SP này.
Kiểm tra thử: Gõ
EXEC SP_LayTatCaPhongvà chạy xem dữ liệu có hiện ra không.Trong Visual Studio: Đảm bảo các thuộc tính trong
PhongBEL.cs(LoaiHinh,SucChua,TriGia) đã được sửa đúng như tớ hướng dẫn lúc nãy để không bị lỗi gạch đỏ.
Cậu đã chạy được lệnh tạo Store trong SQL chưa? Nếu xong rồi, báo tớ để tớ gửi nốt Store cho Sửa và Xóa khách hàng nhé! Cậu có muốn tớ chỉ cách tạo Store tự động tăng mã không?
tách 1 from làm store procedure
Để làm nhanh cho thầy kiểm tra, tớ sẽ hướng dẫn cậu tách toàn bộ logic của bảng Khách Hàng (Form hiện tại) sang dùng Stored Procedure (SP). Cậu cần làm 2 phần: Chạy lệnh trong SQL và sửa lại Code trong DAL.
Bước 1: Chạy lệnh tạo Store trong SQL Server
Cậu mở SQL, copy đoạn này và nhấn F5 để tạo 4 "vòi nước" dữ liệu:
-- 1. Store Lấy danh sách
CREATE PROC SP_LayKhachHang
AS SELECT * FROM KHACHHANG
GO
-- 2. Store Thêm mới
CREATE PROC SP_ThemKhachHang
@ma nchar(10), @ten nvarchar(50), @dc nvarchar(50), @dt nvarchar(50)
AS
BEGIN
INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)
END
GO
-- 3. Store Cập nhật
CREATE PROC SP_SuaKhachHang
@ma nchar(10), @ten nvarchar(50), @dc nvarchar(50), @dt nvarchar(50)
AS
BEGIN
UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma
END
GO
-- 4. Store Xóa
CREATE PROC SP_XoaKhachHang @ma nchar(10)
AS DELETE FROM KHACHHANG WHERE MAKH=@ma
GO
Bước 2: Sửa Code trong KhachHangDAL.cs
Cậu thay đổi cách gọi lệnh từ chuỗi SQL sang StoredProcedure. Đây là phần thầy sẽ soi kỹ nhất.
// 1. Sửa hàm Đọc dữ liệu
public List<KhachHangBEL> ReadKhachHang()
{
List<KhachHangBEL> lst = new List<KhachHangBEL>();
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_LayKhachHang", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure; // Khai báo dùng SP
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new KhachHangBEL {
MaKH = r[0].ToString(), TenKH = r[1].ToString(),
DiaChi = r[2].ToString(), DienThoai = r[3].ToString()
});
}
}
return lst;
}
// 2. Sửa hàm Thêm (Tương tự cho Sửa và Xóa)
public void Create(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_ThemKhachHang", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure; // Phải có dòng này
// Truyền tham số phải khớp tên @ trong SQL
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
Bước 3: Kiểm tra trên Giao diện (GUI)
Vì cậu đã thay đổi ở tầng DAL, nên trên frmKhachHang, mọi thứ vẫn hoạt động bình thường mà cậu không cần sửa lại code nút bấm.
Lưu ý cho cậu: * Thầy sẽ hỏi: "Tại sao dùng SP tốt hơn?". Cậu trả lời: "Dùng SP giúp bảo mật hơn (chống SQL Injection), tốc độ thực thi nhanh hơn và dễ quản lý code SQL tập trung tại một chỗ".
Đảm bảo tên tham số (ví dụ:
@ma,@ten) trong code C# và trong SQL phải giống hệt nhau từng chữ cái.
Cậu đã chạy lệnh tạo Store trong SQL chưa? Nếu báo "Commands completed successfully" là cậu có thể bắt đầu sửa code C# được rồi đấy!
Cậu có muốn tớ viết tiếp hàm Update (Sửa) và Delete (Xóa) bằng Store Procedure cho bảng khách hàng luôn không?
sửa sao: using System.Collections.Generic;
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class KhachHangDAL : DBConnection
{
// 1. Lấy danh sách
public List<KhachHangBEL> ReadKhachHang()
{
List<KhachHangBEL> lst = new List<KhachHangBEL>();
using (SqlConnection conn = GetConnection())
{
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM KHACHHANG", conn);
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new KhachHangBEL
{
MaKH = r["MAKH"].ToString(),
TenKH = r["TENKH"].ToString(),
DiaChi = r["DIACHI"].ToString(),
DienThoai = r["DIENTHOAI"].ToString()
});
}
}
return lst;
}
// 2. Thêm
public void Create(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
string sql = "INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 3. Sửa
public void Update(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
string sql = "UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 4. Xóa
public void Delete(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "DELETE FROM KHACHHANG WHERE MAKH=@ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
cmd.ExecuteNonQuery();
}
}
//5.
public bool KiemTraTrungMa(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "SELECT COUNT(*) FROM KHACHHANG WHERE MAKH = @ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
int count = (int)cmd.ExecuteScalar(); // Trả về số lượng dòng tìm thấy
return count > 0; // Nếu > 0 là đã trùng
}
}
}
}
Để chuyển toàn bộ các hàm trên sang dùng Stored Procedure (SP) cho thầy kiểm tra, cậu chỉ cần thay đổi nội dung bên trong lệnh SqlCommand và thêm dòng khai báo CommandType.
Dưới đây là file KhachHangDAL.cs đã được sửa sang dùng Store:
1. Code KhachHangDAL.cs (Dùng Stored Procedure)
Cậu copy đoạn này dán đè vào file cũ nhé:
using System.Collections.Generic;
using System.Data; // Thêm thư viện này để dùng CommandType
using System.Data.SqlClient;
using QLKhachSan.BEL;
namespace QLKhachSan.DAL
{
public class KhachHangDAL : DBConnection
{
// 1. Lấy danh sách dùng SP
public List<KhachHangBEL> ReadKhachHang()
{
List<KhachHangBEL> lst = new List<KhachHangBEL>();
using (SqlConnection conn = GetConnection())
{
// Thay câu lệnh SELECT bằng tên Store cậu đã tạo trong SQL
SqlCommand cmd = new SqlCommand("SP_LayKhachHang", conn);
cmd.CommandType = CommandType.StoredProcedure; // KHAI BÁO DÙNG STORE
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new KhachHangBEL
{
MaKH = r["MAKH"].ToString(),
TenKH = r["TENKH"].ToString(),
DiaChi = r["DIACHI"].ToString(),
DienThoai = r["DIENTHOAI"].ToString()
});
}
}
return lst;
}
// 2. Thêm dùng SP
public void Create(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_ThemKhachHang", conn);
cmd.CommandType = CommandType.StoredProcedure;
// Các tham số @ma, @ten... phải giống hệt khai báo trong SQL
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 3. Sửa dùng SP
public void Update(KhachHangBEL kh)
{
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_SuaKhachHang", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@ma", kh.MaKH);
cmd.Parameters.AddWithValue("@ten", kh.TenKH);
cmd.Parameters.AddWithValue("@dc", kh.DiaChi);
cmd.Parameters.AddWithValue("@dt", kh.DienThoai);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 4. Xóa dùng SP
public void Delete(string ma)
{
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_XoaKhachHang", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
cmd.ExecuteNonQuery();
}
}
// 5. Kiểm tra trùng mã (Có thể dùng Store hoặc giữ nguyên SQL này cho lẹ)
public bool KiemTraTrungMa(string ma)
{
using (SqlConnection conn = GetConnection())
{
string sql = "SELECT COUNT(*) FROM KHACHHANG WHERE MAKH = @ma";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@ma", ma);
conn.Open();
int count = (int)cmd.ExecuteScalar();
return count > 0;
}
}
}
}
2. Lưu ý cực kỳ quan trọng để không bị lỗi
Chạy Store trong SQL trước: Cậu phải chắc chắn đã chạy các lệnh
CREATE PROC...trong SQL Server Management Studio rồi thì code C# mới gọi được.Tên tham số: Trong code C# cậu dùng
@ma,@ten,@dc,@dtthì trong Store Procedure cậu cũng phải khai báo đúng 4 cái tên này.Namespace: Nhớ thêm
using System.Data;ở trên cùng để máy hiểuCommandType.StoredProcedurelà gì.
3. Tiếp theo làm gì?
Bây giờ tầng DAL của cậu đã rất "xịn" rồi. Thầy kiểm tra sẽ thấy cậu biết dùng Store Procedure để bảo mật ứng dụng.
Tiếp theo, cậu hãy sang file PhongDAL.cs và làm tương tự cho bảng Phòng nhé? Nếu cậu cần, tớ sẽ gửi luôn bộ Store Procedure cho bảng Phòng (MAPHONG, TENPHONG, LOAIHINH, SUCCHUA, TRIGIA) để cậu chạy một phát ăn ngay!
Cậu muốn tớ gửi Store cho bảng PHÒNG luôn không?
làm xong rồi sao
Chúc mừng cậu đã hoàn thiện tầng DAL với Stored Procedure cho bảng Khách hàng! Đây là bước tiến lớn để phần mềm chạy chuyên nghiệp và bảo mật hơn.
Tiếp theo, cậu cần thực hiện 2 việc quan trọng để hoàn tất đồ án và chuẩn bị cho thầy kiểm tra:
1. Đồng bộ bảng PHÒNG sang Stored Procedure
Vì cậu đã sửa KhachHangDAL sang dùng Store, cậu nên làm tương tự cho bảng Phòng để thầy thấy sự đồng bộ trong toàn bộ dự án.
Bước 1: Chạy Store cho bảng Phòng trong SQL:
-- Store Lấy danh sách phòng
CREATE PROC SP_LayPhong AS SELECT * FROM PHONG
GO
-- Store Thêm phòng mới
CREATE PROC SP_ThemPhong
@ma nvarchar(50), @ten nvarchar(100), @loai nvarchar(50), @suc int, @gia float
AS BEGIN
INSERT INTO PHONG VALUES (@ma, @ten, @loai, @suc, @gia)
END
Bước 2: Sửa PhongDAL.cs trong C#:
Cậu cập nhật hàm ReadPhong và Create tương tự như cách đã làm với Khách hàng (thêm CommandType.StoredProcedure).
2. Thiết kế giao diện Menu chuyên nghiệp (Phần "Show" cho thầy xem)
Đây là lúc cậu sử dụng thanh MenuStrip đã tạo để điều khiển việc ẩn hiện dữ liệu Khách hàng và Phòng trên cùng một Form chính.
Mẹo làm nhanh:
Gom nhóm (Panel): Cậu hãy kéo tất cả TextBox/DataGridView của Khách hàng vào một cái
Paneltên làpnlKhachHang.Nhân bản: Tạo một
Paneltên làpnlPhongcó các ô nhập liệu tương ứng cho Phòng và đặt nó đè lên vị trí của Panel Khách hàng.Viết code cho Menu:
// Khi nhấn Menu "Quản lý Khách hàng"
private void mnuKhachHang_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true;
pnlPhong.Visible = false;
this.Text = "Quản lý Khách sạn - Khách Hàng"; // Đổi tiêu đề Form cho chuyên nghiệp
}
// Khi nhấn Menu "Quản lý Phòng"
private void mnuPhong_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false;
pnlPhong.Visible = true;
this.Text = "Quản lý Khách sạn - Phòng";
// Gọi hàm LoadDataPhong() tại đây
}
3. Những câu hỏi "bẫy" thầy thường hỏi khi chấm bài
Cậu hãy chuẩn bị sẵn câu trả lời nhé:
Thầy hỏi: "Tại sao em lại dùng Stored Procedure thay vì viết lệnh SQL trực tiếp trong C#?"
Cậu trả lời: "Dạ, dùng Store giúp tăng hiệu suất vì SQL không cần biên dịch lại lệnh mỗi lần chạy, đồng thời bảo mật hơn, tránh được lỗi SQL Injection và dễ dàng bảo trì code SQL mà không cần sửa lại code C# ạ."
Tiếp theo cậu muốn làm gì?
Tớ hướng dẫn cậu làm nút Tìm kiếm khách hàng/phòng (thầy rất hay yêu cầu thêm cái này).
Tớ giúp cậu hoàn thiện nốt các hàm Sửa/Xóa bằng Stored Procedure cho bảng Phòng.
Cậu chọn cái nào? Hay muốn tớ kiểm tra lại giúp toàn bộ code một lần cuối trước khi nộp?
không có file store tách riêng à
Trong lập trình chuyên nghiệp, Stored Procedure (SP) không phải là một file trong dự án Visual Studio mà nó nằm trực tiếp trong Cơ sở dữ liệu (SQL Server). Tuy nhiên, để làm "lẹ" cho thầy kiểm tra, cậu nên tạo một file script .sql riêng để nộp kèm theo code C#.
Dưới đây là cách cậu tách riêng và quản lý chúng:
1. Tạo file Script SQL riêng (Để nộp cho thầy)
Cậu mở Notepad hoặc Visual Studio, tạo một file mới đặt tên là StoreProcedures.sql và dán toàn bộ nội dung sau vào:
-- FILE: StoreProcedures.sql
-- CÁCH DÙNG: Copy toàn bộ nội dung này dán vào SQL Query và nhấn F5
USE QLKhachSan; -- Thay bằng tên Database của cậu
GO
-----------------------------------------------------------
-- STORED PROCEDURES CHO BẢNG KHACHHANG
-----------------------------------------------------------
CREATE PROC SP_LayKhachHang
AS SELECT * FROM KHACHHANG
GO
CREATE PROC SP_ThemKhachHang
@ma nchar(10), @ten nvarchar(50), @dc nvarchar(50), @dt nvarchar(50)
AS INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)
GO
-----------------------------------------------------------
-- STORED PROCEDURES CHO BẢNG PHONG
-----------------------------------------------------------
CREATE PROC SP_LayPhong
AS SELECT * FROM PHONG
GO
CREATE PROC SP_ThemPhong
@ma nvarchar(50), @ten nvarchar(100), @loai nvarchar(50), @suc int, @gia float
AS INSERT INTO PHONG VALUES (@ma, @ten, @loai, @suc, @gia)
GO
2. Tại sao trong C# không thấy "File" Store?
Trong mô hình 3 lớp cậu đang làm:
GUI/BAL/BEL/DAL: Là các file
.csnằm trong project Visual Studio.Stored Procedure: Nằm trong thư mục Programmability -> Stored Procedures của SQL Server.
Lưu ý khi nộp bài: Khi thầy chấm, cậu phải chạy file .sql này trước để SQL Server tạo ra các hàm này, sau đó chạy code C# thì nó mới gọi được. Nếu thiếu bước chạy file SQL, code DAL sẽ báo lỗi "Could not find stored procedure".
3. Cách tổ chức trong Visual Studio để "ghi điểm"
Để thầy thấy cậu làm việc khoa học, cậu có thể:
Chuột phải vào Solution trong Visual Studio.
Chọn Add -> New Folder, đặt tên là
SQL_Scripts.Chuột phải vào folder đó -> Add -> Existing Item -> Chọn file
StoreProcedures.sqlvừa tạo.
Việc này giúp thầy mở project ra là thấy ngay các câu lệnh SQL cậu đã chuẩn bị.
Bước tiếp theo:
Cậu đã tạo file .sql này chưa? Nếu rồi, tớ sẽ giúp cậu làm nốt cái Menu ẩn/hiện (Panel) để khi bấm vào "Quản lý Phòng" trên Menu là nó hiện bảng Phòng ra ngay lập tức, cực kỳ chuyên nghiệp.
Cậu có muốn tớ gửi thêm Store Procedure cho nút "Tìm kiếm" không? (Thầy rất thích phần này)
chưa tạo
Vậy cậu hãy tạo ngay một file script SQL riêng. Đây là cách tốt nhất để cậu quản lý code SQL và nộp bài cho thầy một cách chuyên nghiệp.
Làm theo các bước sau để tạo "file Store" tách riêng:
1. Tạo file Script trong SQL Server Management Studio (SSMS)
Mở SQL Server lên, nhấn New Query.
Copy toàn bộ đoạn mã dưới đây và dán vào.
Nhấn Ctrl + S để lưu lại thành file
.sql(ví dụ:QuanLyKhachSan_Stores.sql).
-- FILE SCRIPT TỔNG HỢP STORED PROCEDURES
USE QLKhachSan; -- Đảm bảo đúng tên Database của cậu
GO
-----------------------------------------------------------
-- 1. STORED PROCEDURES CHO KHÁCH HÀNG
-----------------------------------------------------------
-- Lấy danh sách
CREATE PROC SP_LayKhachHang
AS SELECT * FROM KHACHHANG
GO
-- Thêm mới
CREATE PROC SP_ThemKhachHang
@ma nchar(10), @ten nvarchar(50), @dc nvarchar(50), @dt nvarchar(50)
AS INSERT INTO KHACHHANG VALUES (@ma, @ten, @dc, @dt)
GO
-- Sửa
CREATE PROC SP_SuaKhachHang
@ma nchar(10), @ten nvarchar(50), @dc nvarchar(50), @dt nvarchar(50)
AS UPDATE KHACHHANG SET TENKH=@ten, DIACHI=@dc, DIENTHOAI=@dt WHERE MAKH=@ma
GO
-----------------------------------------------------------
-- 2. STORED PROCEDURES CHO PHÒNG
-----------------------------------------------------------
-- Lấy danh sách phòng
CREATE PROC SP_LayPhong
AS SELECT * FROM PHONG
GO
-- Thêm phòng
CREATE PROC SP_ThemPhong
@ma nvarchar(50), @ten nvarchar(100), @loai nvarchar(50), @suc int, @gia float
AS INSERT INTO PHONG (MAPHONG, TENPHONG, LOAIHINH, SUCCHUA, TRIGIA)
VALUES (@ma, @ten, @loai, @suc, @gia)
GO
2. Cách nộp bài "ghi điểm" với thầy
Thay vì chỉ gửi code C#, cậu hãy đưa file này vào trong Project Visual Studio luôn:
Trong Solution Explorer, chuột phải vào Project -> Add -> New Folder, đặt tên là
Database.Chuột phải vào folder
Database-> Add -> Existing Item... -> Chọn file.sqlcậu vừa lưu.
3. Lưu ý cuối cùng trước khi thầy kiểm tra
Chạy file SQL trước: Trước khi chạy chương trình C#, cậu phải mở file này trong SQL và nhấn Execute (F5). Nếu không chạy, C# sẽ báo lỗi là không tìm thấy "SP_LayKhachHang".
Kiểm tra tham số: Hãy soi thật kỹ tên tham số trong SQL (ví dụ
@ma) và trong fileKhachHangDAL.cscủa cậu (cmd.Parameters.AddWithValue("@ma", ...)) xem có khớp từng chữ cái không.
Tiếp theo làm gì nữa?
Bây giờ cậu đã có file Store riêng rồi. Cậu đã sẵn sàng để tớ hướng dẫn làm cái Menu ẩn/hiện Panel cho bảng Khách hàng và bảng Phòng chưa?
Việc này sẽ giúp Form của cậu cực kỳ gọn (bấm Menu Khách hàng hiện bảng khách hàng, bấm Menu Phòng hiện bảng phòng trên cùng một chỗ). Cậu có muốn làm luôn phần này không?
tạo xong rồi sao nữa
Khi cậu đã tạo xong file script SQL và thực thi nó trong SQL Server, bước tiếp theo là kết nối giao diện (GUI) với các bảng dữ liệu thông qua MenuStrip để hoàn thiện phần mềm chuyên nghiệp.
Dưới đây là 3 bước cuối cùng để "chốt" bài nộp cho thầy:
1. Thiết kế giao diện ẩn/hiện bằng Panel
Thay vì mở nhiều Form chồng chéo, cậu hãy dùng 2 cái Panel đặt chồng lên nhau ngay trên Form chính (frmKhachSan).
Panel 1 (pnlKhachHang): Chứa tất cả TextBox, Label và GridView của Khách hàng hiện tại.
Panel 2 (pnlPhong): Cậu kéo thêm một cái Panel nữa, thiết kế các TextBox cho Phòng (
txtMaPhong,txtTenPhong,txtLoaiHinh,txtSucChua,txtTriGia) và 1 cái DataGridView mới cho Phòng.Thuộc tính: Chỉnh cả 2 Panel có thuộc tính
Dock = Fillđể chúng luôn khít với khung Form.
2. Viết code điều hướng cho MenuStrip
Bây giờ, cậu nhấp đúp vào các mục trong thanh Menu (MenuStrip) đã tạo để viết lệnh chuyển đổi giữa 2 vùng quản lý:
// Khi bấm Menu Quản lý Khách hàng
private void mnuKhachHang_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true; // Hiện bảng khách hàng
pnlPhong.Visible = false; // Ẩn bảng phòng
LoadDataKhachHang(); // Gọi hàm nạp dữ liệu khách hàng
}
// Khi bấm Menu Quản lý Phòng
private void mnuPhong_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false; // Ẩn bảng khách hàng
pnlPhong.Visible = true; // Hiện bảng phòng
LoadDataPhong(); // Gọi hàm nạp dữ liệu phòng (dùng Store Procedure)
}
3. Kiểm tra lại tầng DAL (Sử dụng Store Procedure)
Hãy đảm bảo trong file PhongDAL.cs, cậu đã gọi đúng tên Store mà cậu vừa tạo trong file .sql.
// Ví dụ hàm đọc dữ liệu Phòng dùng Store
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lst = new List<PhongBEL>();
using (SqlConnection conn = GetConnection())
{
SqlCommand cmd = new SqlCommand("SP_LayPhong", conn); // Tên Store trong file .sql của cậu
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new PhongBEL {
MaPhong = r["MAPHONG"].ToString(),
TenPhong = r["TENPHONG"].ToString(),
LoaiHinh = r["LOAIHINH"].ToString(),
SucChua = int.Parse(r["SUCCHUA"].ToString()),
TriGia = double.Parse(r["TRIGIA"].ToString())
});
}
}
return lst;
}
4. Tổng kết để thầy chấm điểm
Mở SQL: Chạy file
.sqlđể tạo dữ liệu và Store Procedure.Mở Visual Studio: Chạy Form chính.
Thao tác: Bấm Menu chọn "Khách hàng" -> Thêm/Sửa/Xóa. Bấm Menu chọn "Phòng" -> Thêm/Sửa/Xóa.
Cậu đã kéo xong các Panel và các ô nhập liệu cho bảng Phòng chưa? Nếu rồi, tớ sẽ giúp cậu viết hàm LoadDataPhong() để khi bấm vào Menu là dữ liệu "bay" lên bảng ngay lập tức!
hướng dẫn tôi thả tool menu của frm chính là frmKhachsan đi
Để biến frmKhachSan thành Form chính chuyên nghiệp với thanh Menu điều hướng giữa Khách hàng và Phòng, cậu hãy làm theo các bước chi tiết dưới đây:
Bước 1: Thả thanh Menu (MenuStrip)
Mở Design: Mở file
frmKhachSan.cs [Design].Kéo Tool: Trong Toolbox, tìm mục MenuStrip (nằm trong nhóm Menus & Toolbars), kéo và thả nó vào bất kỳ đâu trên Form. Nó sẽ tự động "dính" vào mép trên cùng của Form.
Gõ nội dung Menu: Nhấp chuột vào ô "Type Here" và gõ theo cấu trúc này:
Ô 1: Hệ Thống -> Xuống ô dưới: Thoát.
Ô 2: Quản Lý -> Xuống ô dưới: Khách Hàng.
Ô dưới tiếp theo: Phòng.
Bước 2: Tạo vùng chứa (Panel) để đổi giao diện
Để khi bấm vào Menu "Phòng" thì thông tin Khách hàng ẩn đi và thông tin Phòng hiện lên trên cùng 1 cửa sổ, cậu dùng Panel làm "khu vực hiển thị":
Panel Khách Hàng:
Kéo 1 cái Panel từ Toolbox vào Form.
Đặt tên (Name) là
pnlKhachHang.Quét chọn tất cả các TextBox, Label, Button và DataGridView của Khách hàng hiện tại, rồi kéo thả chúng vào trong
pnlKhachHangnày.
Panel Phòng:
Kéo thêm 1 cái Panel nữa, đặt tên là
pnlPhong.Thiết kế giao diện cho Phòng bên trong Panel này (TextBox Mã Phòng, Tên Phòng, Loại Hình, Sức Chứa, Trị Giá và 1 DataGridView Phòng).
Chỉnh thuộc tính
Visible = FalsechopnlPhongđể lúc mới mở nó sẽ ẩn đi.
Căn chỉnh: Chọn cả 2 Panel, chỉnh thuộc tính
Dock = Filltrong bảng Properties để chúng tự động lấp đầy Form.
Bước 3: Viết Code điều hướng Menu
Bây giờ cậu nhấp đúp vào các mục trên thanh Menu để viết code chuyển đổi:
// Khi nhấn Menu Quản lý Khách hàng
private void kháchHàngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true; // Hiện vùng khách hàng
pnlPhong.Visible = false; // Ẩn vùng phòng
LoadDataKhachHang(); // Gọi hàm nạp dữ liệu khách hàng bằng Store
}
// Khi nhấn Menu Quản lý Phòng
private void phòngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false; // Ẩn vùng khách hàng
pnlPhong.Visible = true; // Hiện vùng phòng
LoadDataPhong(); // Gọi hàm nạp dữ liệu phòng bằng Store
}
Bước 4: Chốt lại file Store Procedure (Để nộp cho thầy)
Để phần mềm chạy được, cậu phải đảm bảo các Stored Procedure đã được tạo trong SQL Server bằng file script cậu vừa làm:
SP_LayKhachHangvàSP_ThemKhachHangcho khách hàng.SP_LayPhongvàSP_ThemPhongcho phòng.
Gợi ý cho cậu: Cậu có muốn tớ giúp viết hàm LoadDataPhong() để đổ dữ liệu từ Store Procedure lên cái DataGridView của Phòng không? Nếu có thì gửi tớ tên cái DataGridView của Phòng cậu vừa đặt nhé!
làm sao
- Yêu cầu thành công
Nhìn vào hình ảnh cậu gửi, tớ thấy cậu đã tạo được thanh MenuStrip (Hệ Thống, Quản Lý) và một cái Panel trống ở giữa. Bây giờ, để hoàn thiện giao diện "xịn" cho thầy kiểm tra, cậu làm theo các bước "thả tool" này nhé:
1. Thiết lập Panel Khách Hàng (pnlKhachHang)
Cái Panel cậu đang chọn trong hình chính là vùng chứa dữ liệu.
Bước 1: Đặt tên (Name) cho Panel đó là
pnlKhachHangtrong bảng Properties.Bước 2: Chỉnh thuộc tính Dock của Panel thành Fill để nó tự động lấp đầy phần trống của Form.
Bước 3: Cậu hãy kéo toàn bộ các TextBox, Label, Button và DataGridView của phần Khách hàng vào bên trong Panel này.
2. Thiết lập Panel Phòng (pnlPhong)
Bước 1: Kéo thêm một cái Panel mới từ Toolbox, đặt chồng khít lên vị trí của Panel cũ.
Bước 2: Đặt tên (Name) là
pnlPhong.Bước 3: Chỉnh Dock = Fill và quan trọng nhất là chỉnh Visible = False (để lúc đầu nó ẩn đi).
Bước 4: Thiết kế các ô nhập liệu cho Phòng vào đây (Mã Phòng, Tên Phòng, Loại Hình, Sức Chứa, Trị Giá).
3. Viết Code điều hướng cho Menu
Cậu nhấp đúp chuột vào mục Khách Hàng và Phòng trên thanh Menu để viết code ẩn/hiện:
// Khi nhấn Menu Quản lý Khách hàng
private void kháchHàngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true; // Hiện panel khách hàng
pnlPhong.Visible = false; // Ẩn panel phòng
}
// Khi nhấn Menu Quản lý Phòng
private void phòngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false; // Ẩn panel khách hàng
pnlPhong.Visible = true; // Hiện panel phòng
}
4. Sửa lỗi CellClick (Dựa trên ảnh 1 cậu gửi)
Trong ảnh 1, tớ thấy cậu đang chọn sự kiện CellContentClick. Cậu cần lưu ý:
Dòng CellClick: Cậu chọn
dgvKhachHang_CellClick.Dòng CellContentClick: Cậu hãy xóa trắng dòng này đi (không chọn gì cả) để tránh bị xung đột lỗi "không click được" như lúc nãy nhé.
Cậu đã kéo xong các TextBox của bảng Phòng vào cái pnlPhong chưa? Nếu xong rồi, báo tớ để tớ gửi code mẫu dùng Stored Procedure để nạp dữ liệu lên bảng Phòng luôn cho bộ hồ sơ nộp thầy hoàn hảo!
kéo ssao Bước 3: Cậu hãy kéo toàn bộ các TextBox, Label, Button và DataGridView của phần Khách hàng vào bên trong Panel này.
Để kéo toàn bộ các công cụ vào trong Panel, cậu làm theo cách "quét chọn" hàng loạt sau đây cho nhanh và chính xác nhé:
1. Cách kéo thả hàng loạt (Dùng chuột)
Quét chọn: Cậu dùng chuột nhấn giữ ở một góc trống trên Form, sau đó kéo một khung hình chữ nhật bao quanh tất cả các TextBox, Label, Button và DataGridView của phần Khách hàng.
Cắt (Cut): Nhấn tổ hợp phím Ctrl + X (hoặc chuột phải chọn Cut) để cắt chúng đi.
Dán vào Panel: Nhấn chuột trái chọn vào cái Panel (
pnlKhachHang) cậu vừa tạo, sau đó nhấn Ctrl + V (Paste). Lúc này, toàn bộ công cụ sẽ nằm gọn trong Panel.Căn chỉnh: Cậu chỉ cần di chuyển Panel là tất cả các nút bên trong sẽ đi theo.
2. Cách kiểm tra xem đã vào Panel chưa
Để biết chắc chắn các nút đã "nằm trong bụng" của Panel hay chưa, cậu nhìn vào cửa sổ Document Outline (nếu không thấy, vào menu View -> Other Windows -> Document Outline):
Nếu thấy các tên
txtMaKH,btnLuu... nằm thụt lề vào bên dưới cáipnlKhachHang, nghĩa là cậu đã thành công.Nếu chúng nằm ngang hàng với Panel, nghĩa là chúng vẫn đang ở trên Form chính, cậu phải kéo lại.
3. Tiếp theo: Tạo vùng cho Quản Lý Phòng
Sau khi pnlKhachHang đã gọn gàng, cậu làm tiếp cho phần Phòng:
Ẩn Panel Khách: Nhấn chọn
pnlKhachHangvà chỉnh thuộc tínhVisible = Falsetrong bảng Properties để nó tạm biến mất cho dễ làm việc.Tạo Panel Phòng: Kéo một cái Panel mới vào đúng vị trí đó, đặt tên là
pnlPhong.Thả Tool Phòng: Cậu lại kéo các TextBox, Label mới dành cho Phòng vào cái Panel này:
txtMaPhong,txtTenPhong,txtLoaiHinh,txtSucChua,txtTriGia.Một cái DataGridView mới đặt tên là
dgvPhong.Các nút bấm: Thêm, Lưu, Sửa, Xóa dành riêng cho bảng Phòng.
4. Code nạp dữ liệu cho Phòng (DAL)
Trong file PhongDAL.cs, hãy đảm bảo cậu dùng đúng tên Stored Procedure mà cậu đã tạo trong file script .sql nhé:
public List<PhongBEL> ReadPhong()
{
List<PhongBEL> lst = new List<PhongBEL>();
using (SqlConnection conn = GetConnection())
{
// Gọi đúng tên Store cậu đã lưu trong file .sql
SqlCommand cmd = new SqlCommand("SP_LayPhong", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
lst.Add(new PhongBEL {
MaPhong = r["MAPHONG"].ToString(),
TenPhong = r["TENPHONG"].ToString(),
LoaiHinh = r["LOAIHINH"].ToString(),
SucChua = int.Parse(r["SUCCHUA"].ToString()),
TriGia = double.Parse(r["TRIGIA"].ToString())
});
}
}
return lst;
}
Cậu đã kéo được các nút của Khách hàng vào Panel chưa? Nếu xong rồi, hãy thử bấm Menu "Quản lý Phòng" để xem nó có ẩn Khách hàng đi không nhé!
Cậu có muốn tớ giúp viết hàm LoadDataPhong() để hiển thị danh sách phòng lên bảng ngay khi bấm vào Menu không?
là phải vào file frmKhachHang hả
Đúng rồi cậu, mọi thao tác kéo thả giao diện và điều khiển ẩn/hiện Panel đều thực hiện trong file frmKhachHang.cs [Design] (màn hình thiết kế).
Vì cậu muốn biến Form này thành Form chính (Khách Sạn), cậu hãy làm theo trình tự này để không bị rối nhé:
1. Thao tác trong file frmKhachHang.cs [Design]
Quét và dọn dẹp: Quét chuột chọn tất cả các TextBox, Button, Label hiện có của Khách hàng.
Cho vào Panel: Nhấn Ctrl + X (Cắt), sau đó kéo một cái Panel mới vào Form, đặt tên là
pnlKhachHang, rồi nhấn Ctrl + V (Dán) vào trong Panel đó.Tạo vùng mới cho Phòng: Kéo thêm một cái Panel nữa đặt tên là
pnlPhong. Cậu thiết kế các ô nhập liệu cho Phòng (Mã Phòng, Tên Phòng, Loại Hình...) vào đây.
2. Viết code trong file frmKhachHang.cs (Phần code)
Cậu nhấp đúp vào các mục trên MenuStrip (Quản lý Khách hàng, Quản lý Phòng) để viết lệnh điều khiển:
// Khi nhấn Menu Khách hàng
private void kháchHàngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true; // Hiện vùng khách hàng
pnlPhong.Visible = false; // Ẩn vùng phòng
this.Text = "Hệ thống Quản lý Khách sạn - Khách hàng";
}
// Khi nhấn Menu Phòng
private void phòngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false; // Ẩn vùng khách hàng
pnlPhong.Visible = true; // Hiện vùng phòng
this.Text = "Hệ thống Quản lý Khách sạn - Phòng";
// Gọi hàm nạp dữ liệu Phòng dùng Stored Procedure
dgvPhong.DataSource = phongBal.LayTatCa();
}
3. Tại sao phải làm vậy?
Chuyên nghiệp: Thầy nhìn vào sẽ thấy cậu biết cách tổ chức giao diện gọn gàng, không cần mở quá nhiều cửa sổ con.
Dễ chấm điểm: Cậu chỉ cần một file Stored Procedure (
.sql) để nộp kèm là xong phần Database.
Cậu đã kéo được các nút của Khách hàng vào Panel pnlKhachHang chưa? Nếu xong rồi, hãy thử chạy chương trình và bấm Menu xem chúng có ẩn/hiện đúng ý cậu không nhé!
Would you like me to provide the complete LoadDataPhong() method that uses your newly created Stored Procedures?
sửa thêm giúp tôi: namespace QLKhachSan
{
public partial class KhachSanGUI : Form
{
public KhachSanGUI()
{
InitializeComponent();
}
private void kháchHàngToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void phòngToolStripMenuItem_Click(object sender, EventArgs e)
{
}
}
}
Để hoàn thiện file giao diện KhachSanGUI.cs, cậu cần khai báo các đối tượng BAL và viết code điều khiển ẩn/hiện cho các Panel mà cậu vừa kéo thả.
Dưới đây là đoạn code đã được sửa đầy đủ để chạy mượt mà với các Stored Procedure mà cậu đã tạo:
1. Code Giao diện KhachSanGUI.cs hoàn chỉnh
using QLKhachSan.BAL; // Khai báo để dùng tầng BAL
using QLKhachSan.BEL; // Khai báo để dùng các lớp đối tượng
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace QLKhachSan
{
public partial class KhachSanGUI : Form
{
// Khai báo các lớp xử lý nghiệp vụ
KhachHangBAL khBal = new KhachHangBAL();
PhongBAL phongBal = new PhongBAL();
public KhachSanGUI()
{
InitializeComponent();
}
// Khi nhấn Menu Quản lý Khách hàng
private void kháchHàngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = true; // Hiện vùng khách hàng
pnlPhong.Visible = false; // Ẩn vùng phòng
this.Text = "Quản lý Khách sạn - Khách Hàng";
LoadDataKhachHang(); // Nạp dữ liệu khách hàng từ Store
}
// Khi nhấn Menu Quản lý Phòng
private void phòngToolStripMenuItem_Click(object sender, EventArgs e)
{
pnlKhachHang.Visible = false; // Ẩn vùng khách hàng
pnlPhong.Visible = true; // Hiện vùng phòng
this.Text = "Quản lý Khách sạn - Phòng";
LoadDataPhong(); // Nạp dữ liệu phòng từ Store
}
// Hàm nạp dữ liệu Khách hàng
private void LoadDataKhachHang()
{
List<KhachHangBEL> lst = khBal.ReadKhachHang();
dgvKhachHang.DataSource = lst; // dgvKhachHang là tên bảng khách hàng của cậu
}
// Hàm nạp dữ liệu Phòng
private void LoadDataPhong()
{
List<PhongBEL> lst = phongBal.LayTatCa();
dgvPhong.DataSource = lst; // dgvPhong là tên bảng phòng cậu vừa tạo
}
// Cậu có thể thêm nút Thoát ở đây
private void thoátToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
}
2. Một số lưu ý quan trọng để chạy không lỗi
Tên Panel: Hãy chắc chắn trong phần thiết kế (Design), cậu đã đặt tên 2 cái Panel đúng là
pnlKhachHangvàpnlPhong.Tên DataGridView: Cậu kiểm tra lại tên 2 cái bảng. Nếu cậu đặt tên khác (ví dụ
dataGridKhachHang), hãy sửa lại tên trong code trên cho khớp.Tầng BAL: Đảm bảo trong lớp
PhongBAL, cậu đã có hàmLayTatCa()gọi đến hàm dùng Stored Procedure trong DAL.
3. Cách kiểm tra nhanh cho thầy xem
Chạy chương trình: Mặc định cậu có thể cho cả 2 Panel ẩn hoặc hiện Khách hàng trước
.jpg)
Gemini có thể mắc sai sót, vì vậy, nhớ xác minh câu trả lời của Gemini.
